1. 程式人生 > 實用技巧 >網路協議學習筆記(一)通訊協議綜述

網路協議學習筆記(一)通訊協議綜述

概述

網路知識是計算機最重要的一部分知識之一,我們常常遇到線上的bug大部分和網路有關係,尤其是分散式的叢集中,如果想解決問題,就繞不開檢視網路狀態和網路連線的日誌。現在我給大家分享一下網路的一些基礎知識。

網路協議介紹

我們常見的網路協議見下圖,我們就以下面的網路協議,來說明一下網路協議的基礎介紹。

網路協議的流程

我們通過電商支付的例子來說明這個過程都走了哪些協議,你先在瀏覽器裡面輸入 https://www.Tmall.com ,這是一個 URL。瀏覽器只知道名字是“www.kaola.com”,但是不知道具體的地點,所以不知道應該如何訪問。於是,它開啟地址簿去查詢。可以使用一般的地址簿協議 DNS 去查詢,還可以使用另一種更加精準的地址簿查詢協議 HTTPDNS。無論用哪一種方法查詢,最終都會得到這個地址:106.114.138.24。這個是 IP 地址,是網際網路世界的“門牌號”。知道了目標地址,瀏覽器就開始打包它的請求。對於普通的瀏覽請求,往往會使用 HTTP 協議;但是對於購物的請求,往往需要進行加密傳輸,因而會使用 HTTPS 協議。無論是什麼協議,裡面都會寫明“你要買什麼和買多少”。

DNS、HTTP、HTTPS 所在的層我們稱為應用層。經過應用層封裝後,瀏覽器會將應用層的包交給下一層去完成,通過 socket 程式設計來實現。下一層是傳輸層。傳輸層有兩種協議,一種是無連線的協議 UDP,一種是面向連線的協議 TCP。對於支付來講,往往使用 TCP 協議。所謂的面向連線就是,TCP 會保證這個包能夠到達目的地。如果不能到達,就會重新發送,直至到達。

TCP 協議裡面會有兩個埠,一個是瀏覽器監聽的埠,一個是電商的伺服器監聽的埠。作業系統往往通過埠來判斷,它得到的包應該給哪個程序。

傳輸層封裝完畢後,瀏覽器會將包交給作業系統的網路層。網路層的協議是 IP 協議。在 IP 協議裡面會有源 IP 地址,即瀏覽器所在機器的 IP 地址和目標 IP 地址,也即電商網站所在伺服器的 IP 地址。

作業系統既然知道了目標 IP 地址,就開始想如何根據這個門牌號找到目標機器。作業系統往往會判斷,這個目標 IP 地址是本地人,還是外地人。如果是本地人,從門牌號就能看出來,但是顯然電商網站不在本地,而在遙遠的地方。作業系統知道要離開本地去遠方。雖然不知道遠方在何處,但是可以這樣類比一下:如果去國外要去海關,去外地就要去閘道器。而作業系統啟動的時候,就會被 DHCP 協議配置 IP 地址,以及預設的閘道器的 IP 地址 192.168.1.1。作業系統如何將 IP 地址發給閘道器呢?在本地通訊基本靠吼,於是作業系統大吼一聲,誰是 192.168.1.1 啊?閘道器會回答它,我就是,我的本地地址在村東頭。這個本地地址就是 MAC 地址,而大吼的那一聲是 ARP 協議。

於是作業系統將 IP 包交給了下一層,也就是 MAC 層。網絡卡再將包發出去。由於這個包裡面是有 MAC 地址的,因而它能夠到達閘道器。閘道器收到包之後,會根據自己的知識,判斷下一步應該怎麼走。閘道器往往是一個路由器,到某個 IP 地址應該怎麼走,這個叫作路由表。路由器有點像玄奘西行路過的一個個國家的一個個城關。每個城關都連著兩個國家,每個國家相當於一個區域網,在每個國家內部,都可以使用本地的地址 MAC 進行通訊。一旦跨越城關,就需要拿出 IP 頭來,裡面寫著貧僧來自東土大唐(就是源 IP 地址),欲往西天拜佛求經(指的是目標 IP 地址)。路過寶地,借宿一晚,明日啟程,請問接下來該怎麼走啊?

城關往往是知道這些“知識”的,因為城關和臨近的城關也會經常溝通。到哪裡應該怎麼走,這種溝通的協議稱為路由協議,常用的有 OSPF 和 BGP。

城關與城關之間是一個國家,當網路包知道了下一步去哪個城關,還是要使用國家內部的 MAC 地址,通過下一個城關的 MAC 地址,找到下一個城關,然後再問下一步的路怎麼走,一直到走出最後一個城關。最後一個城關知道這個網路包要去的地方。於是,對著這個國家吼一聲,誰是目標 IP 啊?目標伺服器就會回覆一個 MAC 地址。網路包過關後,通過這個 MAC 地址就能找到目標伺服器。目標伺服器發現 MAC 地址對上了,取下 MAC 頭來,傳送給作業系統的網路層。發現 IP 也對上了,就取下 IP 頭。IP 頭裡會寫上一層封裝的是 TCP 協議,然後將其交給傳輸層,即 TCP 層。在這一層裡,對於收到的每個包,都會有一個回覆的包說明收到了。這個回覆的包絕非這次下單請求的結果,例如購物是否成功,扣了多少錢等,而僅僅是 TCP 層的一個說明,即收到之後的回覆。當然這個回覆,會沿著剛才來的方向走回去,報個平安。因為一旦出了國門,西行路上千難萬險,如果在這個過程中,網路包走丟了,例如進了大沙漠,或者被強盜搶劫殺害怎麼辦呢?因而到了要報個平安。如果過一段時間還是沒到,傳送端的 TCP 層會重新發送這個包,還是上面的過程,直到有一天收到平安到達的回覆。這個重試絕非你的瀏覽器重新將下單這個動作重新請求一次。對於瀏覽器來講,就傳送了一次下單請求,TCP 層不斷自己悶頭重試。除非 TCP 這一層出了問題,例如連線斷了,才輪到瀏覽器的應用層重新發送下單請求。當網路包平安到達 TCP 層之後,TCP 頭中有目標埠號,通過這個埠號,可以找到電商網站的程序正在監聽這個埠號,假設一個 Tomcat,將這個包發給電商網站。

電商網站的程序得到 HTTP 請求的內容,知道了要買東西,買多少。往往一個電商網站最初接待請求的這個 Tomcat 只是個接待員,負責統籌處理這個請求,而不是所有的事情都自己做。例如,這個接待員要告訴專門管理訂單的程序,登記要買某個商品,買多少,要告訴管理庫存的程序,庫存要減少多少,要告訴支付的程序,應該付多少錢,等等。如何告訴相關的程序呢?往往通過 RPC 呼叫,即遠端過程呼叫的方式來實現。遠端過程呼叫就是當告訴管理訂單程序的時候,接待員不用關心中間的網路互連問題,會由 RPC 框架統一處理。RPC 框架有很多種,有基於 HTTP 協議放在 HTTP 的報文裡面的,有直接封裝在 TCP 報文裡面的。當接待員發現相應的部門都處理完畢,就回復一個 HTTPS 的包,告知下單成功。這個 HTTPS 的包,會像來的時候一樣,經過千難萬險到達你的個人電腦,最終進入瀏覽器,顯示支付成功。

程式是如何工作的

我們簡單想象一下我們開啟url的過程。

經常有人會問這樣一個問題,我都知道那臺機器的 IP 地址了,直接發給他訊息唄,要 MAC 地址幹啥?這裡的關鍵就是,沒有 MAC 地址訊息是發不出去的。所以如果一個 HTTP 協議的包跑在網路上,它一定是完整的。無論這個包經過哪些裝置,它都是完整的。所謂的二層裝置、三層裝置,都是這些裝置上跑的程式不同而已。一個 HTTP 協議的包經過一個二層裝置,二層裝置收進去的是整個網路包。這裡面 HTTP、TCP、 IP、 MAC 都有。什麼叫二層裝置呀,就是隻把 MAC 頭摘下來,看看到底是丟棄、轉發,還是自己留著。那什麼叫三層裝置呢?就是把 MAC 頭摘下來之後,再把 IP 頭摘下來,看看到底是丟棄、轉發,還是自己留著。

當一個網路包從一個網口經過的時候,你看到了,首先先看看要不要請進來,處理一把。有的網口配置了混雜模式,凡是經過的,全部拿進來。拿進來以後,就要交給一段程式來處理。於是,你呼叫 process_layer2(buffer)。當然,這是一個假的函式。但是你明白其中的意思,知道肯定是有這麼個函式的。那這個函式是幹什麼的呢?從 Buffer 中,摘掉二層的頭,看一看,應該根據頭裡面的內容做什麼操作。

假設你發現這個包的 MAC 地址和你的相符,那說明就是發給你的,於是需要呼叫 process_layer3(buffer)。這個時候,Buffer 裡面往往就沒有二層的頭了,因為已經在上一個函式的處理過程中拿掉了,或者將開始的偏移量移動了一下。在這個函式裡面,摘掉三層的頭,看看到底是傳送給自己的,還是希望自己轉發出去的。如何判斷呢?如果 IP 地址不是自己的,那就應該轉發出去;如果 IP 地址是自己的,那就是發給自己的。根據 IP 頭裡面的標示,拿掉三層的頭,進行下一層的處理,到底是呼叫 process_tcp(buffer) 呢,還是呼叫 process_udp(buffer) 呢?

假設這個地址是 TCP 的,則會呼叫 process_tcp(buffer)。這時候,Buffer 裡面沒有三層的頭,就需要檢視四層的頭,看這是一個發起,還是一個應答,又或者是一個正常的資料包,然後分別由不同的邏輯進行處理。如果是發起或者應答,接下來可能要傳送一個回覆包;如果是一個正常的資料包,就需要交給上層了。交給誰呢?是不是有 process_http(buffer) 函式呢?沒有的,如果你是一個網路包處理程式,你不需要有 process_http(buffer),而是應該交給應用去處理。交給哪個應用呢?在四層的頭裡面有埠號,不同的應用監聽不同的埠號。如果發現瀏覽器應用在監聽這個埠,那你發給瀏覽器就行了。至於瀏覽器怎麼處理,和你沒有關係。

瀏覽器自然是解析 HTML,顯示出頁面來。電腦的主人看到頁面很開心,就點了滑鼠。點選滑鼠的動作被瀏覽器捕獲。瀏覽器知道,又要發起另一個 HTTP 請求了,於是使用埠號,將請求發給了你。你應該呼叫 send_tcp(buffer)。不用說,Buffer 裡面就是 HTTP 請求的內容。這個函式裡面加一個 TCP 的頭,記錄下源埠號。瀏覽器會給你目的埠號,一般為 80 埠。然後呼叫 send_layer3(buffer)。Buffer 裡面已經有了 HTTP 的頭和內容,以及 TCP 的頭。在這個函式裡面加一個 IP 的頭,記錄下源 IP 的地址和目標 IP 的地址。然後呼叫 send_layer2(buffer)。Buffer 裡面已經有了 HTTP 的頭和內容、TCP 的頭,以及 IP 的頭。這個函式裡面要加一下 MAC 的頭,記錄下源 MAC 地址,得到的就是本機器的 MAC 地址和目標的 MAC 地址。不過,這個還要看當前知道不知道,知道就直接加上;不知道的話,就要通過一定的協議處理過程,找到 MAC 地址。反正要填一個,不能空著。萬事俱備,只要 Buffer 裡面的內容完整,就可以從網口發出去了,你作為一個程式的任務就算告一段落了。

網路為什麼要分層

這裡我們先探討第一個問題,網路為什麼要分層?因為,是個複雜的程式都要分層。理解計算機網路中的概念,一個很好的角度是,想象網路包就是一段 Buffer,或者一塊記憶體,是有格式的。同時,想象自己是一個處理網路包的程式,而且這個程式可以跑在電腦上,可以跑在伺服器上,可以跑在交換機上,也可以跑在路由器上。你想象自己有很多的網口,從某個口拿進一個網路包來,用自己的程式處理一下,再從另一個網口傳送出去。當然網路包的格式很複雜,這個程式也很複雜。複雜的程式都要分層,這是程式設計的要求。比如,複雜的電商還會分資料庫層、快取層、Compose 層、Controller 層和接入層,每一層專注做本層的事情。

再看看把分層比喻人員組織結構的例子。總經理握手,不需要員工在吧,總經理之間談什麼,不需要員工參與吧,但是網路世界不是這樣的。正確的應該是,總經理之間溝通的時候,經理將總經理放在自己兜裡,然後組長把經理放自己兜裡,員工把組長放自己兜裡,像套娃娃一樣。那員工直接溝通,不帶上總經理,就不恰當了。現實生活中,往往是員工說一句,組長補充兩句,然後經理補充兩句,最後總經理再補充兩句。但是在網路世界,應該是總經理說話,經理補充兩句,組長補充兩句,員工再補充兩句。

那 TCP 在三次握手的時候,IP 層和 MAC 層在做什麼呢?當然是 TCP 傳送每一個訊息,都會帶著 IP 層和 MAC 層了。因為,TCP 每傳送一個訊息,IP 層和 MAC 層的所有機制都要執行一遍。而你只看到 TCP 三次握手了,其實,IP 層和 MAC 層為此也忙活好久了。這裡要記住一點:只要是在網路上跑的包,都是完整的。可以有下層沒上層,絕對不可能有上層沒下層。所以,對 TCP 協議來說,三次握手也好,重試也好,只要想發出去包,就要有 IP 層和 MAC 層,不然是發不出去的。

經常有人會問這樣一個問題,我都知道那臺機器的 IP 地址了,直接發給他訊息唄,要 MAC 地址幹啥?這裡的關鍵就是,沒有 MAC 地址訊息是發不出去的。所以如果一個 HTTP 協議的包跑在網路上,它一定是完整的。無論這個包經過哪些裝置,它都是完整的。所謂的二層裝置、三層裝置,都是這些裝置上跑的程式不同而已。一個 HTTP 協議的包經過一個二層裝置,二層裝置收進去的是整個網路包。這裡面 HTTP、TCP、 IP、 MAC 都有。什麼叫二層裝置呀,就是隻把 MAC 頭摘下來,看看到底是丟棄、轉發,還是自己留著。那什麼叫三層裝置呢?就是把 MAC 頭摘下來之後,再把 IP 頭摘下來,看看到底是丟棄、轉發,還是自己留著。

IP ADDR的那些事

我們在linux伺服器執行命令ip addr的時候經常返回。

 1 root@test:~# ip addr
 2 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
 3     link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 4     inet 127.0.0.1/8 scope host lo
 5        valid_lft forever preferred_lft forever
 6     inet6 ::1/128 scope host 
 7        valid_lft forever preferred_lft forever
 8 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
 9     link/ether fa:16:3e:c7:79:75 brd ff:ff:ff:ff:ff:ff
10     inet 10.100.122.2/24 brd 10.100.122.255 scope global eth0
11        valid_lft forever preferred_lft forever
12     inet6 fe80::f816:3eff:fec7:7975/64 scope link 
13        valid_lft forever preferred_lft forever

這個命令顯示了這臺機器上所有的網絡卡。大部分的網絡卡都會有一個 IP 地址,當然,這不是必須的。在後面的分享中,我們會遇到沒有 IP 地址的情況。IP 地址是一個網絡卡在網路世界的通訊地址,相當於我們現實世界的門牌號碼。既然是門牌號碼,不能大家都一樣,不然就會起衝突。比方說,假如大家都叫六單元 1001 號,那快遞就找不到地方了。所以,有時候咱們的電腦彈出網路地址衝突,出現上不去網的情況,多半是 IP 地址衝突了。

如上輸出的結果,10.100.122.2 就是一個 IP 地址。這個地址被點分隔為四個部分,每個部分 8 個 bit,所以 IP 地址總共是 32 位。這樣產生的 IP 地址的數量很快就不夠用了。因為當時設計 IP 地址的時候,哪知道今天會有這麼多的計算機啊!因為不夠用,於是就有了 IPv6,也就是上面輸出結果裡面 inet6 fe80::f816:3eff:fec7:7975/64。這個有 128 位,現在看來是夠了,但是未來的事情誰知道呢?本來 32 位的 IP 地址就不夠,還被分成了 5 類。現在想想,當時分配地址的時候,真是太奢侈了。

在網路地址中,至少在當時設計的時候,對於 A、B、 C 類主要分兩部分,前面一部分是網路號,後面一部分是主機號。這很好理解,大家都是六單元 1001 號,我是小區 A 的六單元 1001 號,而你是小區 B 的六單元 1001 號。下面這個表格,詳細地展示了 A、B、C 三類地址所能包含的主機的數量。在後文中,我也會多次藉助這個表格來講解。

這裡面有個尷尬的事情,就是 C 類地址能包含的最大主機數量實在太少了,只有 254 個。當時設計的時候恐怕沒想到,現在估計一個網咖都不夠用吧。而 B 類地址能包含的最大主機數量又太多了。6 萬多臺機器放在一個網路下面,一般的企業基本達不到這個規模,閒著的地址就是浪費。

無型別域間選路(CIDR)

於是有了一個折中的方式叫作無型別域間選路,簡稱 CIDR。這種方式打破了原來設計的幾類地址的做法,將 32 位的 IP 地址一分為二,前面是網路號,後面是主機號。從哪裡分呢?你如果注意觀察的話可以看到,10.100.122.2/24,這個 IP 地址中有一個斜槓,斜槓後面有個數字 24。這種地址表示形式,就是 CIDR。後面 24 的意思是,32 位中,前 24 位是網路號,後 8 位是主機號。

伴隨著 CIDR 存在的,一個是廣播地址,10.100.122.255。如果傳送這個地址,所有 10.100.122 網路裡面的機器都可以收到。另一個是子網掩碼,255.255.255.0。將子網掩碼和 IP 地址進行 AND 計算。前面三個 255,轉成二進位制都是 1。1 和任何數值取 AND,都是原來數值,因而前三個數不變,為 10.100.122。後面一個 0,轉換成二進位制是 0,0 和任何數值取 AND,都是 0,因而最後一個數變為 0,合起來就是 10.100.122.0。這就是網路號。將子網掩碼和 IP 地址按位計算 AND,就可得到網路號。

公有 IP 地址和私有 IP 地址

在日常的工作中,幾乎不用劃分 A 類、B 類或者 C 類,所以時間長了,很多人就忘記了這個分類,而只記得 CIDR。但是有一點還是要注意的,就是公有 IP 地址和私有 IP 地址。

我們繼續看上面的表格。表格最右列是私有 IP 地址段。平時我們看到的資料中心裡,辦公室、家裡或學校的 IP 地址,一般都是私有 IP 地址段。因為這些地址允許組織內部的 IT 人員自己管理、自己分配,而且可以重複。因此,你學校的某個私有 IP 地址段和我學校的可以是一樣的。這就像每個小區有自己的樓編號和門牌號,你們小區可以叫 6 棟,我們小區也叫 6 棟,沒有任何問題。但是一旦出了小區,就需要使用公有 IP 地址。就像人民路 888 號,是國家統一分配的,不能兩個小區都叫人民路 888 號。公有 IP 地址有個組織統一分配,你需要去買。如果你搭建一個網站,給你學校的人使用,讓你們學校的 IT 人員給你一個 IP 地址就行。但是假如你要做一個類似網易 163 這樣的網站,就需要有公有 IP 地址,這樣全世界的人才能訪問。表格中的 192.168.0.x 是最常用的私有 IP 地址。你家裡有 Wi-Fi,對應就會有一個 IP 地址。一般你家裡地上網裝置不會超過 256 個,所以 /24 基本就夠了。有時候我們也能見到 /16 的 CIDR,這兩種是最常見的,也是最容易理解的。不需要將十進位制轉換為二進位制 32 位,就能明顯看出 192.168.0 是網路號,後面是主機號。而整個網路裡面的第一個地址 192.168.0.1,往往就是你這個私有網路的出口地址。例如,你家裡的電腦連線 Wi-Fi,Wi-Fi 路由器的地址就是 192.168.0.1,而 192.168.0.255 就是廣播地址。一旦傳送這個地址,整個 192.168.0 網路裡面的所有機器都能收到。但是也不總都是這樣的情況。因此,其他情況往往就會很難理解,還容易出錯。

舉例:一個容易“犯錯”的 CIDR

我們來看 16.158.165.91/22 這個 CIDR。求一下這個網路的第一個地址、子網掩碼和廣播地址。你要是上來就寫 16.158.165.1,那就大錯特錯了。/22 不是 8 的整數倍,不好辦,只能先變成二進位制來看。16.158 的部分不會動,它佔了前 16 位。中間的 165,變為二進位制為‭10100101‬。除了前面的 16 位,還剩 6 位。所以,這 8 位中前 6 位是網路號,16.158.<101001>,而 <01>.91 是機器號。第一個地址是 16.158.<101001><00>.1,即 16.158.164.1。子網掩碼是 255.255.<111111><00>.0,即 255.255.252.0。廣播地址為 16.158.<101001><11>.255,即 16.158.167.255。這五類地址中,還有一類 D 類是組播地址。使用這一類地址,屬於某個組的機器都能收到。這有點類似在公司裡面大家都加入了一個郵件組。傳送郵件,加入這個組的都能收到。組播地址在後面講述 VXLAN 協議的時候會提到。講了這麼多,才講了上面的輸出結果中很小的一部分,是不是覺得原來並沒有真的理解 ip addr 呢?我們接著來分析。在 IP 地址的後面有個 scope,對於 eth0 這張網絡卡來講,是 global,說明這張網絡卡是可以對外的,可以接收來自各個地方的包。對於 lo 來講,是 host,說明這張網絡卡僅僅可以供本機相互通訊。lo 全稱是 loopback,又稱環回介面,往往會被分配到 127.0.0.1 這個地址。這個地址用於本機通訊,經過核心處理後直接返回,不會在任何網路中出現。

MAC 地址

在 IP 地址的上一行是 link/ether fa:16:3e:c7:79:75 brd ff:ff:ff:ff:ff:ff,這個被稱為 MAC 地址,是一個網絡卡的實體地址,用十六進位制,6 個 byte 表示。MAC 地址是一個很容易讓人“誤解”的地址。因為 MAC 地址號稱全域性唯一,不會有兩個網絡卡有相同的 MAC 地址,而且網絡卡自生產出來,就帶著這個地址。很多人看到這裡就會想,既然這樣,整個網際網路的通訊,全部用 MAC 地址好了,只要知道了對方的 MAC 地址,就可以把資訊傳過去。這樣當然是不行的。 一個網路包要從一個地方傳到另一個地方,除了要有確定的地址,還需要有定位功能。 而有門牌號碼屬性的 IP 地址,才是有遠端定位功能的。例如,你去杭州市網商路 599 號 B 樓 6 層找劉超,你在路上問路,可能被問的人不知道 B 樓是哪個,但是可以給你指網商路怎麼去。但是如果你問一個人,你知道這個身份證號的人在哪裡嗎?可想而知,沒有人知道。MAC 地址更像是身份證,是一個唯一的標識。它的唯一性設計是為了組網的時候,不同的網絡卡放在一個網路裡面的時候,可以不用擔心衝突。從硬體角度,保證不同的網絡卡有不同的標識。MAC 地址是有一定定位功能的,只不過範圍非常有限。你可以根據 IP 地址,找到杭州市網商路 599 號 B 樓 6 層,但是依然找不到我,你就可以靠吼了,大聲喊身份證 XXXX 的是哪位?我聽到了,我就會站起來說,是我啊。但是如果你在上海,到處喊身份證 XXXX 的是哪位,我不在現場,當然不會回答,因為我在杭州不在上海。所以,MAC 地址的通訊範圍比較小,侷限在一個子網裡面。例如,從 192.168.0.2/24 訪問 192.168.0.3/24 是可以用 MAC 地址的。一旦跨子網,即從 192.168.0.2/24 到 192.168.1.2/24,MAC 地址就不行了,需要 IP 地址起作用了。

網路裝置的狀態標識

解析完了 MAC 地址,我們再來看<broadcast,multicast,up,lower_up>是幹什麼的?這個叫做 net_device flags,網路裝置的狀態標識。UP 表示網絡卡處於啟動的狀態;BROADCAST 表示這個網絡卡有廣播地址,可以傳送廣播包;MULTICAST 表示網絡卡可以傳送多播包;LOWER_UP 表示 L1 是啟動的,也即網線插著呢。MTU1500 是指什麼意思呢?是哪一層的概念呢?最大傳輸單元 MTU 為 1500,這是乙太網的預設值。上一節,我們講過網路包是層層封裝的。MTU 是二層 MAC 層的概念。MAC 層有 MAC 的頭,乙太網規定連 MAC 頭帶正文合起來,不允許超過 1500 個位元組。正文裡面有 IP 的頭、TCP 的頭、HTTP 的頭。如果放不下,就需要分片來傳輸。qdisc pfifo_fast 是什麼意思呢?qdisc 全稱是 queueing discipline,中文叫排隊規則。核心如果需要通過某個網路介面傳送資料包,它都需要按照為這個介面配置的 qdisc(排隊規則)把資料包加入佇列。最簡單的 qdisc 是 pfifo,它不對進入的資料包做任何的處理,資料包採用先入先出的方式通過佇列。pfifo_fast 稍微複雜一些,它的佇列包括三個波段(band)。在每個波段裡面,使用先進先出規則。三個波段(band)的優先順序也不相同。band 0 的優先順序最高,band 2 的最低。如果 band 0 裡面有資料包,系統就不會處理 band 1 裡面的資料包,band 1 和 band 2 之間也是一樣。資料包是按照服務型別(Type of Service,TOS)被分配到三個波段(band)裡面的。TOS 是 IP 頭裡面的一個欄位,代表了當前的包是高優先順序的,還是低優先順序的。佇列是個好東西,後面我們講雲端計算中的網路的時候,會有很多使用者共享一個網路出口的情況,這個時候如何排隊,每個佇列有多粗,佇列處理速度應該怎麼提升,我都會詳細為你講解。

DHCP與PXE

你看著它有自己的源 IP 地址 16.158.23.6,也有目標 IP 地址 192.168.1.6,但是包發不出去,這是因為 MAC 層還沒填。自己的 MAC 地址自己知道,這個容易。但是目標 MAC 填什麼呢?是不是填 192.168.1.6 這臺機器的 MAC 地址呢?當然不是。Linux 首先會判斷,要去的這個地址和我是一個網段的嗎,或者和我的一個網絡卡是同一網段的嗎?只有是一個網段的,它才會傳送 ARP 請求,獲取 MAC 地址。如果發現不是呢?Linux 預設的邏輯是,如果這是一個跨網段的呼叫,它便不會直接將包傳送到網路上,而是企圖將包傳送到閘道器。如果你配置了閘道器的話,Linux 會獲取閘道器的 MAC 地址,然後將包發出去。對於 192.168.1.6 這臺機器來講,雖然路過它家門的這個包,目標 IP 是它,但是無奈 MAC 地址不是它的,所以它的網絡卡是不會把包收進去的。如果沒有配置閘道器呢?那包壓根就發不出去。如果將閘道器配置為 192.168.1.6 呢?不可能,Linux 不會讓你配置成功的,因為閘道器要和當前的網路至少一個網絡卡是同一個網段的,怎麼可能 16.158.23.6 的閘道器是 192.168.1.6 呢?所以,當你需要手動配置一臺機器的網路 IP 時,一定要好好問問你的網路管理員。如果在機房裡面,要去網路管理員那裡申請,讓他給你分配一段正確的 IP 地址。當然,真正配置的時候,一定不是直接用命令配置的,而是放在一個配置檔案裡面。不同系統的配置檔案格式不同,但是無非就是 CIDR、子網掩碼、廣播地址和閘道器地址。

動態主機配置協議(DHCP)

原來配置 IP 有這麼多門道兒啊。你可能會問了,配置了 IP 之後一般不能變的,配置一個服務端的機器還可以,但是如果是客戶端的機器呢?我抱著一臺膝上型電腦在公司裡走來走去,或者白天來晚上走,每次使用都要配置 IP 地址,那可怎麼辦?還有人事、行政等非技術人員,如果公司所有的電腦都需要 IT 人員配置,肯定忙不過來啊。因此,我們需要有一個自動配置的協議,也就是動態主機配置協議(Dynamic Host Configuration Protocol),簡稱 DHCP。

解析 DHCP 的工作方式

當一臺機器新加入一個網路的時候,肯定一臉懵,啥情況都不知道,只知道自己的 MAC 地址。怎麼辦?先吼一句,我來啦,有人嗎?這時候的溝通基本靠“吼”。這一步,我們稱為 DHCP Discover。新來的機器使用 IP 地址 0.0.0.0 傳送了一個廣播包,目的 IP 地址為 255.255.255.255。廣播包封裝了 UDP,UDP 封裝了 BOOTP。其實 DHCP 是 BOOTP 的增強版,但是如果你去抓包的話,很可能看到的名稱還是 BOOTP 協議。在這個廣播包裡面,新人大聲喊:我是新來的(Boot request),我的 MAC 地址是這個,我還沒有 IP,誰能給租給我個 IP 地址!格式就像這樣:

如果一個網路管理員在網路裡面配置了 DHCP Server 的話,他就相當於這些 IP 的管理員。他立刻能知道來了一個“新人”。這個時候,我們可以體會 MAC 地址唯一的重要性了。當一臺機器帶著自己的 MAC 地址加入一個網路的時候,MAC 是它唯一的身份,如果連這個都重複了,就沒辦法配置了。只有 MAC 唯一,IP 管理員才能知道這是一個新人,需要租給它一個 IP 地址,這個過程我們稱為 DHCP Offer。同時,DHCP Server 為此客戶保留為它提供的 IP 地址,從而不會為其他 DHCP 客戶分配此 IP 地址。DHCP Offer 的格式就像這樣,裡面有給新人分配的地址。

DHCP Server 仍然使用廣播地址作為目的地址,因為,此時請求分配 IP 的新人還沒有自己的 IP。DHCP Server 回覆說,我分配了一個可用的 IP 給你,你看如何?除此之外,伺服器還發送了子網掩碼、閘道器和 IP 地址租用期等資訊。新來的機器很開心,它的“吼”得到了回覆,並且有人願意租給它一個 IP 地址了,這意味著它可以在網路上立足了。當然更令人開心的是,如果有多個 DHCP Server,這臺新機器會收到多個 IP 地址,簡直受寵若驚。它會選擇其中一個 DHCP Offer,一般是最先到達的那個,並且會向網路傳送一個 DHCP Request 廣播資料包,包中包含客戶端的 MAC 地址、接受的租約中的 IP 地址、提供此租約的 DHCP 伺服器地址等,並告訴所有 DHCP Server 它將接受哪一臺伺服器提供的 IP 地址,告訴其他 DHCP 伺服器,謝謝你們的接納,並請求撤銷它們提供的 IP 地址,以便提供給下一個 IP 租用請求者。

此時,由於還沒有得到 DHCP Server 的最後確認,客戶端仍然使用 0.0.0.0 為源 IP 地址、255.255.255.255 為目標地址進行廣播。在 BOOTP 裡面,接受某個 DHCP Server 的分配的 IP。當 DHCP Server 接收到客戶機的 DHCP request 之後,會廣播返回給客戶機一個 DHCP ACK 訊息包,表明已經接受客戶機的選擇,並將這一 IP 地址的合法租用資訊和其他的配置資訊都放入該廣播包,發給客戶機,歡迎它加入網路大家庭。

IP 地址的收回和續租

既然是租房子,就是有租期的。租期到了,管理員就要將 IP 收回。如果不用的話,收回就收回了。就像你租房子一樣,如果還要續租的話,不能到了時間再續租,而是要提前一段時間給房東說。DHCP 也是這樣。客戶機會在租期過去 50% 的時候,直接向為其提供 IP 地址的 DHCP Server 傳送 DHCP request 訊息包。客戶機接收到該伺服器迴應的 DHCP ACK 訊息包,會根據包中所提供的新的租期以及其他已經更新的 TCP/IP 引數,更新自己的配置。這樣,IP 租用更新就完成了。好了,一切看起來完美。DHCP 協議大部分人都知道,但是其實裡面隱藏著一個細節,很多人可能不會去注意。接下來,我就講一個有意思的事情:網路管理員不僅能自動分配 IP 地址,還能幫你自動安裝作業系統!

預啟動執行環境(PXE)

普通的膝上型電腦,一般不會有這種需求。因為你拿到電腦時,就已經有作業系統了,即便你自己重灌作業系統,也不是很麻煩的事情。但是,在資料中心裡就不一樣了。資料中心裡面的管理員可能一下子就拿到幾百臺空的機器,一個個安裝作業系統,會累死的。所以管理員希望的不僅僅是自動分配 IP 地址,還要自動安裝系統。裝好系統之後自動分配 IP 地址,直接啟動就能用了,這樣當然最好了!這事兒其實仔細一想,還是挺有難度的。安裝作業系統,應該有個光碟吧。資料中心裡不能用光碟吧,想了一個辦法就是,可以將光盤裡面要安裝的作業系統放在一個伺服器上,讓客戶端去下載。但是客戶端放在哪裡呢?它怎麼知道去哪個伺服器上下載呢?客戶端總得安裝在一個作業系統上呀,可是這個客戶端本來就是用來安裝作業系統的呀?其實,這個過程和作業系統啟動的過程有點兒像。首先,啟動 BIOS。這是一個特別小的小系統,只能幹特別小的一件事情。其實就是讀取硬碟的 MBR 啟動扇區,將 GRUB 啟動起來;然後將權力交給 GRUB,GRUB 載入核心、載入作為根檔案系統的 initramfs 檔案;然後將權力交給核心;最後核心啟動,初始化整個作業系統。那我們安裝作業系統的過程,只能插在 BIOS 啟動之後了。因為沒安裝系統之前,連啟動扇區都沒有。因而這個過程叫做預啟動執行環境(Pre-boot Execution Environment),簡稱 PXE。

PXE 協議分為客戶端和伺服器端,由於還沒有作業系統,只能先把客戶端放在 BIOS 裡面。當計算機啟動時,BIOS 把 PXE 客戶端調入記憶體裡面,就可以連線到服務端做一些操作了。首先,PXE 客戶端自己也需要有個 IP 地址。因為 PXE 的客戶端啟動起來,就可以傳送一個 DHCP 的請求,讓 DHCP Server 給它分配一個地址。PXE 客戶端有了自己的地址,那它怎麼知道 PXE 伺服器在哪裡呢?對於其他的協議,都好辦,要有人告訴他。例如,告訴瀏覽器要訪問的 IP 地址,或者在配置中告訴它;例如,微服務之間的相互呼叫。但是 PXE 客戶端啟動的時候,啥都沒有。好在 DHCP Server 除了分配 IP 地址以外,還可以做一些其他的事情。這裡有一個 DHCP Server 的一個樣例配置:

 1 ddns-update-style interim;
 2 ignore client-updates;
 3 allow booting;
 4 allow bootp;
 5 subnet 192.168.1.0 netmask 255.255.255.0
 6 {
 7 option routers 192.168.1.1;
 8 option subnet-mask 255.255.255.0;
 9 option time-offset -18000;
10 default-lease-time 21600;
11 max-lease-time 43200;
12 range dynamic-bootp 192.168.1.240 192.168.1.250;
13 filename "pxelinux.0";
14 next-server 192.168.1.180;
15 }

按照上面的原理,預設的 DHCP Server 是需要配置的,無非是我們配置 IP 的時候所需要的 IP 地址段、子網掩碼、閘道器地址、租期等。如果想使用 PXE,則需要配置 next-server,指向 PXE 伺服器的地址,另外要配置初始啟動檔案 filename。這樣 PXE 客戶端啟動之後,傳送 DHCP 請求之後,除了能得到一個 IP 地址,還可以知道 PXE 伺服器在哪裡,也可以知道如何從 PXE 伺服器上下載某個檔案,去初始化作業系統。

解析 PXE 的工作過程

接下來我們來詳細看一下 PXE 的工作過程。首先,啟動 PXE 客戶端。第一步是通過 DHCP 協議告訴 DHCP Server,我剛來,一窮二白,啥都沒有。DHCP Server 便租給它一個 IP 地址,同時也給它 PXE 伺服器的地址、啟動檔案 pxelinux.0。

其次,PXE 客戶端知道要去 PXE 伺服器下載這個檔案後,就可以初始化機器。於是便開始下載,下載的時候使用的是 TFTP 協議。所以 PXE 伺服器上,往往還需要有一個 TFTP 伺服器。PXE 客戶端向 TFTP 伺服器請求下載這個檔案,TFTP 伺服器說好啊,於是就將這個檔案傳給它。

然後,PXE 客戶端收到這個檔案後,就開始執行這個檔案。這個檔案會指示 PXE 客戶端,向 TFTP 伺服器請求計算機的配置資訊 pxelinux.cfg。TFTP 伺服器會給 PXE 客戶端一個配置檔案,裡面會說核心在哪裡、initramfs 在哪裡。PXE 客戶端會請求這些檔案。

最後,啟動 Linux 核心。一旦啟動了作業系統,以後就啥都好辦了。

總結

以後關於資料中臺系列的總結大部分來自Geek Time的課件,大家可以自行關鍵字搜尋。