關(guān)于 Linux 網(wǎng)絡(luò),你必須知道這些

我們一起學(xué)習(xí)了文件系統(tǒng)和磁盤 I/O 的工作原理,以及相應(yīng)的性能分析和優(yōu)化方法。接下來(lái),我們將進(jìn)入下一個(gè)重要模塊—— Linux 的網(wǎng)絡(luò)子系統(tǒng)。

由于網(wǎng)絡(luò)處理的流程最復(fù)雜,跟我們前面講到的進(jìn)程調(diào)度、中斷處理、內(nèi)存管理以及 I/O 等都密不可分,所以,我把網(wǎng)絡(luò)模塊作為最后一個(gè)資源模塊來(lái)講解。

同 CPU、內(nèi)存以及 I/O 一樣,網(wǎng)絡(luò)也是 Linux 系統(tǒng)最核心的功能。網(wǎng)絡(luò)是一種把不同計(jì)算機(jī)或網(wǎng)絡(luò)設(shè)備連接到一起的技術(shù),它本質(zhì)上是一種進(jìn)程間通信方式,特別是跨系統(tǒng)的進(jìn)程間通信,必須要通過(guò)網(wǎng)絡(luò)才能進(jìn)行。隨著高并發(fā)、分布式、云計(jì)算、微服務(wù)等技術(shù)的普及,網(wǎng)絡(luò)的性能也變得越來(lái)越重要。

網(wǎng)絡(luò)模型

說(shuō)到網(wǎng)絡(luò),我想你肯定經(jīng)常提起七層負(fù)載均衡、四層負(fù)載均衡,或者三層設(shè)備、二層設(shè)備等等。那么,這里說(shuō)的二層、三層、四層、七層又都是什么意思呢?

實(shí)際上,這些層都來(lái)自國(guó)際標(biāo)準(zhǔn)化組織制定的開(kāi)放式系統(tǒng)互聯(lián)通信參考模型(Open System Interconnection Reference Model),簡(jiǎn)稱為 OSI 網(wǎng)絡(luò)模型。

  • 應(yīng)用層,負(fù)責(zé)為應(yīng)用程序提供統(tǒng)一的接口
  • 表示層,負(fù)責(zé)把數(shù)據(jù)轉(zhuǎn)換成兼容接收系統(tǒng)的格式
  • 會(huì)話層,負(fù)責(zé)維護(hù)計(jì)算機(jī)之間的通信連接
  • 傳輸層,負(fù)責(zé)為數(shù)據(jù)加上傳輸表頭,形成數(shù)據(jù)包
  • 網(wǎng)絡(luò)層,負(fù)責(zé)數(shù)據(jù)的路由和轉(zhuǎn)發(fā)
  • 數(shù)據(jù)鏈路層,負(fù)責(zé) MAC 尋址、錯(cuò)誤偵測(cè)和改錯(cuò)
  • 物理層,負(fù)責(zé)在物理網(wǎng)絡(luò)中傳輸數(shù)據(jù)幀

但是 OSI 模型還是太復(fù)雜了,也沒(méi)能提供一個(gè)可實(shí)現(xiàn)的方法。所以,在 Linux 中,我們實(shí)際上使用的是另一個(gè)更實(shí)用的四層模型,即 TCP/IP 網(wǎng)絡(luò)模型。

TCP/IP 模型,把網(wǎng)絡(luò)互聯(lián)的框架分為應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、網(wǎng)絡(luò)接口層等四層,其中,

  • 應(yīng)用層,負(fù)責(zé)向用戶提供一組應(yīng)用程序,比如 HTTP、FTP、DNS 等。
  • 傳輸層,負(fù)責(zé)端到端的通信,比如 TCP、UDP 等。
  • 網(wǎng)絡(luò)層,負(fù)責(zé)網(wǎng)絡(luò)包的封裝、尋址和路由,比如 IP、ICMP 等。
  • 網(wǎng)絡(luò)接口層,負(fù)責(zé)網(wǎng)絡(luò)包在物理網(wǎng)絡(luò)中的傳輸,比如 MAC 尋址、錯(cuò)誤偵測(cè)以及通過(guò)網(wǎng)卡傳輸網(wǎng)絡(luò)幀等。

為了幫你更形象理解 TCP/IP 與 OSI 模型的關(guān)系,我畫了一張圖,如下所示:


image.png

當(dāng)然了,雖說(shuō) Linux 實(shí)際按照 TCP/IP 模型,實(shí)現(xiàn)了網(wǎng)絡(luò)協(xié)議棧,但在平時(shí)的學(xué)習(xí)交流中,我們習(xí)慣上還是用 OSI 七層模型來(lái)描述。比如,說(shuō)到七層和四層負(fù)載均衡,對(duì)應(yīng)的分別是 OSI 模型中的應(yīng)用層和傳輸層(而它們對(duì)應(yīng)到 TCP/IP 模型中,實(shí)際上是四層和三層)。

OSI七層和TCP/IP四層的關(guān)系

OSI引入了服務(wù)、接口、協(xié)議、分層的概念,TCP/IP借鑒了OSI的這些概念建立TCP/IP模型。

OSI先有模型,后有協(xié)議,先有標(biāo)準(zhǔn),后進(jìn)行實(shí)踐;而TCP/IP則相反,先有協(xié)議和應(yīng)用再提出了模型,且是參照的OSI模型。

OSI是一種理論下的模型,而TCP/IP已被廣泛使用,成為網(wǎng)絡(luò)互聯(lián)事實(shí)上的標(biāo)準(zhǔn)。

Linux 網(wǎng)絡(luò)棧

有了 TCP/IP 模型后,在進(jìn)行網(wǎng)絡(luò)傳輸時(shí),數(shù)據(jù)包就會(huì)按照協(xié)議棧,對(duì)上一層發(fā)來(lái)的數(shù)據(jù)進(jìn)行逐層處理;然后封裝上該層的協(xié)議頭,再發(fā)送給下一層。

當(dāng)然,網(wǎng)絡(luò)包在每一層的處理邏輯,都取決于各層采用的網(wǎng)絡(luò)協(xié)議。比如在應(yīng)用層,一個(gè)提供 REST API 的應(yīng)用,可以使用 HTTP 協(xié)議,把它需要傳輸?shù)?JSON 數(shù)據(jù)封裝到 HTTP 協(xié)議中,然后向下傳遞給 TCP 層。

而封裝做的事情就很簡(jiǎn)單了,只是在原來(lái)的負(fù)載前后,增加固定格式的元數(shù)據(jù),原始的負(fù)載數(shù)據(jù)并不會(huì)被修改。

比如,以通過(guò) TCP 協(xié)議通信的網(wǎng)絡(luò)包為例,通過(guò)下面這張圖,我們可以看到,應(yīng)用程序數(shù)據(jù)在每個(gè)層的封裝格式。

image.png

這些新增的頭部和尾部,增加了網(wǎng)絡(luò)包的大小,但我們都知道,物理鏈路中并不能傳輸任意大小的數(shù)據(jù)包。網(wǎng)絡(luò)接口配置的最大傳輸單元(MTU),就規(guī)定了最大的 IP 包大小。在我們最常用的以太網(wǎng)中,MTU 默認(rèn)值是 1500(這也是 Linux 的默認(rèn)值)。

一旦網(wǎng)絡(luò)包超過(guò) MTU 的大小,就會(huì)在網(wǎng)絡(luò)層分片,以保證分片后的 IP 包不大于 MTU 值。顯然,MTU 越大,需要的分包也就越少,自然,網(wǎng)絡(luò)吞吐能力就越好。

理解了 TCP/IP 網(wǎng)絡(luò)模型和網(wǎng)絡(luò)包的封裝原理后,你很容易能想到,Linux 內(nèi)核中的網(wǎng)絡(luò)棧,其實(shí)也類似于 TCP/IP 的四層結(jié)構(gòu)。如下圖所示,就是 Linux 通用 IP 網(wǎng)絡(luò)棧的示意圖:

image.png

我們從上到下來(lái)看這個(gè)網(wǎng)絡(luò)棧,你可以發(fā)現(xiàn),

  • 最上層的應(yīng)用程序,需要通過(guò)系統(tǒng)調(diào)用,來(lái)跟套接字接口進(jìn)行交互;
  • 套接字的下面,就是我們前面提到的傳輸層、網(wǎng)絡(luò)層和網(wǎng)絡(luò)接口層;
  • 最底層,則是網(wǎng)卡驅(qū)動(dòng)程序以及物理網(wǎng)卡設(shè)備。

這里我簡(jiǎn)單說(shuō)一下網(wǎng)卡。網(wǎng)卡是發(fā)送和接收網(wǎng)絡(luò)包的基本設(shè)備。在系統(tǒng)啟動(dòng)過(guò)程中,網(wǎng)卡通過(guò)內(nèi)核中的網(wǎng)卡驅(qū)動(dòng)程序注冊(cè)到系統(tǒng)中。而在網(wǎng)絡(luò)收發(fā)過(guò)程中,內(nèi)核通過(guò)中斷跟網(wǎng)卡進(jìn)行交互。

再結(jié)合前面提到的 Linux 網(wǎng)絡(luò)棧,可以看出,網(wǎng)絡(luò)包的處理非常復(fù)雜。所以,網(wǎng)卡硬中斷只處理最核心的網(wǎng)卡數(shù)據(jù)讀取或發(fā)送,而協(xié)議棧中的大部分邏輯,都會(huì)放到軟中斷中處理。

Linux 網(wǎng)絡(luò)收發(fā)流程

我們先來(lái)看網(wǎng)絡(luò)包的接收流程。

當(dāng)一個(gè)網(wǎng)絡(luò)幀到達(dá)網(wǎng)卡后,網(wǎng)卡會(huì)通過(guò) DMA 方式,把這個(gè)網(wǎng)絡(luò)包放到收包隊(duì)列中;然后通過(guò)硬中斷,告訴中斷處理程序已經(jīng)收到了網(wǎng)絡(luò)包。

接著,網(wǎng)卡中斷處理程序會(huì)為網(wǎng)絡(luò)幀分配內(nèi)核數(shù)據(jù)結(jié)構(gòu)(sk_buff),并將其拷貝到 sk_buff 緩沖區(qū)中;然后再通過(guò)軟中斷,通知內(nèi)核收到了新的網(wǎng)絡(luò)幀。

接下來(lái),內(nèi)核協(xié)議棧從緩沖區(qū)中取出網(wǎng)絡(luò)幀,并通過(guò)網(wǎng)絡(luò)協(xié)議棧,從下到上逐層處理這個(gè)網(wǎng)絡(luò)幀。比如,

  • 在鏈路層檢查報(bào)文的合法性,找出上層協(xié)議的類型(比如 IPv4 還是 IPv6),再去掉幀頭、幀尾,然后交給網(wǎng)絡(luò)層。
  • 網(wǎng)絡(luò)層取出 IP 頭,判斷網(wǎng)絡(luò)包下一步的走向,比如是交給上層處理還是轉(zhuǎn)發(fā)。當(dāng)網(wǎng)絡(luò)層確認(rèn)這個(gè)包是要發(fā)送到本機(jī)后,就會(huì)取出上層協(xié)議的類型(比如 TCP 還是 UDP),去掉 IP 頭,再交給傳輸層處理。
  • 傳輸層取出 TCP 頭或者 UDP 頭后,根據(jù) < 源 IP、源端口、目的 IP、目的端口 > 四元組作為標(biāo)識(shí),找出對(duì)應(yīng)的 Socket,并把數(shù)據(jù)拷貝到 Socket 的接收緩存中。

最后,應(yīng)用程序就可以使用 Socket 接口,讀取到新接收到的數(shù)據(jù)了。

為了更清晰表示這個(gè)流程,我畫了一張圖,這張圖的左半部分表示接收流程,而圖中的粉色箭頭則表示網(wǎng)絡(luò)包的處理路徑。


image.png

網(wǎng)絡(luò)包的發(fā)送流程

了解網(wǎng)絡(luò)包的接收流程后,就很容易理解網(wǎng)絡(luò)包的發(fā)送流程。網(wǎng)絡(luò)包的發(fā)送流程就是上圖的右半部分,很容易發(fā)現(xiàn),網(wǎng)絡(luò)包的發(fā)送方向,正好跟接收方向相反。

首先,應(yīng)用程序調(diào)用 Socket API(比如 sendmsg)發(fā)送網(wǎng)絡(luò)包。

由于這是一個(gè)系統(tǒng)調(diào)用,所以會(huì)陷入到內(nèi)核態(tài)的套接字層中。套接字層會(huì)把數(shù)據(jù)包放到 Socket 發(fā)送緩沖區(qū)中。

接下來(lái),網(wǎng)絡(luò)協(xié)議棧從 Socket 發(fā)送緩沖區(qū)中,取出數(shù)據(jù)包;再按照 TCP/IP 棧,從上到下逐層處理。比如,傳輸層和網(wǎng)絡(luò)層,分別為其增加 TCP 頭和 IP 頭,執(zhí)行路由查找確認(rèn)下一跳的 IP,并按照 MTU 大小進(jìn)行分片。

分片后的網(wǎng)絡(luò)包,再送到網(wǎng)絡(luò)接口層,進(jìn)行物理地址尋址,以找到下一跳的 MAC 地址。然后添加幀頭和幀尾,放到發(fā)包隊(duì)列中。這一切完成后,會(huì)有軟中斷通知驅(qū)動(dòng)程序:發(fā)包隊(duì)列中有新的網(wǎng)絡(luò)幀需要發(fā)送。

最后,驅(qū)動(dòng)程序通過(guò) DMA ,從發(fā)包隊(duì)列中讀出網(wǎng)絡(luò)幀,并通過(guò)物理網(wǎng)卡把它發(fā)送出去。

小結(jié)

多臺(tái)服務(wù)器通過(guò)網(wǎng)卡、交換機(jī)、路由器等網(wǎng)絡(luò)設(shè)備連接到一起,構(gòu)成了相互連接的網(wǎng)絡(luò)。由于網(wǎng)絡(luò)設(shè)備的異構(gòu)性和網(wǎng)絡(luò)協(xié)議的復(fù)雜性,國(guó)際標(biāo)準(zhǔn)化組織定義了一個(gè)七層的 OSI 網(wǎng)絡(luò)模型,但是這個(gè)模型過(guò)于復(fù)雜,實(shí)際工作中的事實(shí)標(biāo)準(zhǔn),是更為實(shí)用的 TCP/IP 模型。

TCP/IP 模型,把網(wǎng)絡(luò)互聯(lián)的框架,分為應(yīng)用層、傳輸層、網(wǎng)絡(luò)層、網(wǎng)絡(luò)接口層等四層,這也是 Linux 網(wǎng)絡(luò)棧最核心的構(gòu)成部分。

  • 應(yīng)用程序通過(guò)套接字接口發(fā)送數(shù)據(jù)包,先要在網(wǎng)絡(luò)協(xié)議棧中從上到下進(jìn)行逐層處理,最終再送到網(wǎng)卡發(fā)送出去。
  • 而接收時(shí),同樣先經(jīng)過(guò)網(wǎng)絡(luò)棧從下到上的逐層處理,最終才會(huì)送到應(yīng)用程序。

FAQ

我結(jié)合網(wǎng)絡(luò)上查閱的資料和文章中的內(nèi)容,總結(jié)了下網(wǎng)卡收發(fā)報(bào)文的過(guò)程,不知道是否正確:

  1. 內(nèi)核分配一個(gè)主內(nèi)存地址段(DMA緩沖區(qū)),網(wǎng)卡設(shè)備可以在DMA緩沖區(qū)中讀寫數(shù)據(jù)(應(yīng)該是網(wǎng)絡(luò)包到了之后,才分配DMA緩沖區(qū)
    )
  2. 當(dāng)來(lái)了一個(gè)網(wǎng)絡(luò)包,網(wǎng)卡將網(wǎng)絡(luò)包寫入DMA緩沖區(qū),寫完后通知CPU產(chǎn)生硬中斷
  3. 硬中斷處理程序鎖定當(dāng)前DMA緩沖區(qū),然后將網(wǎng)絡(luò)包拷貝到另一塊內(nèi)存區(qū),清空并解鎖當(dāng)前DMA緩沖區(qū),然后通知軟中斷去處理網(wǎng)絡(luò)包。

當(dāng)發(fā)送數(shù)據(jù)包時(shí),與上述相反。鏈路層將數(shù)據(jù)包封裝完畢后,放入網(wǎng)卡的DMA緩沖區(qū),并調(diào)用系統(tǒng)硬中斷,通知網(wǎng)卡從緩沖區(qū)讀取并發(fā)送數(shù)據(jù)。

了解 Linux 網(wǎng)絡(luò)的基本原理和收發(fā)流程后,你肯定迫不及待想知道,如何去觀察網(wǎng)絡(luò)的性能情況。具體而言,哪些指標(biāo)可以用來(lái)衡量 Linux 的網(wǎng)絡(luò)性能呢?

性能指標(biāo)

實(shí)際上,我們通常用帶寬、吞吐量、延時(shí)、PPS(Packet Per Second)等指標(biāo)衡量網(wǎng)絡(luò)的性能。

  • 帶寬,表示鏈路的最大傳輸速率,單位通常為 b/s (比特 / 秒)
  • 吞吐量,表示單位時(shí)間內(nèi)成功傳輸?shù)臄?shù)據(jù)量,單位通常為 b/s(比特 / 秒)或者 B/s(字節(jié) / 秒)。吞吐量受帶寬限制,而吞吐量 / 帶寬,也就是該網(wǎng)絡(luò)的使用率。
  • 延時(shí),表示從網(wǎng)絡(luò)請(qǐng)求發(fā)出后,一直到收到遠(yuǎn)端響應(yīng),所需要的時(shí)間延遲。在不同場(chǎng)景中,這一指標(biāo)可能會(huì)有不同含義。比如,它可以表示,建立連接需要的時(shí)間(比如 TCP 握手延時(shí)),或一個(gè)數(shù)據(jù)包往返所需的時(shí)間(比如 RTT)。
  • PPS,是 Packet Per Second(包 / 秒)的縮寫,表示以網(wǎng)絡(luò)包為單位的傳輸速率。PPS 通常用來(lái)評(píng)估網(wǎng)絡(luò)的轉(zhuǎn)發(fā)能力,比如硬件交換機(jī),通??梢赃_(dá)到線性轉(zhuǎn)發(fā)(即 PPS 可以達(dá)到或者接近理論最大值)。而基于 Linux 服務(wù)器的轉(zhuǎn)發(fā),則容易受網(wǎng)絡(luò)包大小的影響。

除了這些指標(biāo),網(wǎng)絡(luò)的可用性(網(wǎng)絡(luò)能否正常通信)、并發(fā)連接數(shù)(TCP 連接數(shù)量)、丟包率(丟包百分比)、重傳率(重新傳輸?shù)木W(wǎng)絡(luò)包比例)等也是常用的性能指標(biāo)。

網(wǎng)絡(luò)配置

分析網(wǎng)絡(luò)問(wèn)題的第一步,通常是查看網(wǎng)絡(luò)接口的配置和狀態(tài)。你可以使用 ifconfig 或者 ip 命令,來(lái)查看網(wǎng)絡(luò)的配置。我個(gè)人更推薦使用 ip 工具,因?yàn)樗峁┝烁S富的功能和更易用的接口。

ifconfig 和 ip 分別屬于軟件包 net-tools 和 iproute2,iproute2 是 net-tools 的下一代。通常情況下它們會(huì)在發(fā)行版中默認(rèn)安裝。但如果你找不到 ifconfig 或者 ip 命令,可以安裝這兩個(gè)軟件包。

以網(wǎng)絡(luò)接口 eth0 為例,你可以運(yùn)行下面的兩個(gè)命令,查看它的配置和狀態(tài):


$ ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
      inet 10.240.0.30 netmask 255.240.0.0 broadcast 10.255.255.255
      inet6 fe80::20d:3aff:fe07:cf2a prefixlen 64 scopeid 0x20<link>
      ether 78:0d:3a:07:cf:3a txqueuelen 1000 (Ethernet)
      RX packets 40809142 bytes 9542369803 (9.5 GB)
      RX errors 0 dropped 0 overruns 0 frame 0
      TX packets 32637401 bytes 4815573306 (4.8 GB)
      TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
?
$ ip -s addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
  link/ether 78:0d:3a:07:cf:3a brd ff:ff:ff:ff:ff:ff
  inet 10.240.0.30/12 brd 10.255.255.255 scope global eth0
      valid_lft forever preferred_lft forever
  inet6 fe80::20d:3aff:fe07:cf2a/64 scope link
      valid_lft forever preferred_lft forever
  RX: bytes packets errors dropped overrun mcast
   9542432350 40809397 0       0       0       193
  TX: bytes packets errors dropped carrier collsns
   4815625265 32637658 0       0       0       0

你可以看到,ifconfig 和 ip 命令輸出的指標(biāo)基本相同,只是顯示格式略微不同。比如,它們都包括了網(wǎng)絡(luò)接口的狀態(tài)標(biāo)志、MTU 大小、IP、子網(wǎng)、MAC 地址以及網(wǎng)絡(luò)包收發(fā)的統(tǒng)計(jì)信息。

第一,網(wǎng)絡(luò)接口的狀態(tài)標(biāo)志。ifconfig 輸出中的 RUNNING ,或 ip 輸出中的 LOWER_UP ,都表示物理網(wǎng)絡(luò)是連通的,即網(wǎng)卡已經(jīng)連接到了交換機(jī)或者路由器中。如果你看不到它們,通常表示網(wǎng)線被拔掉了。

第二,MTU 的大小。MTU 默認(rèn)大小是 1500,根據(jù)網(wǎng)絡(luò)架構(gòu)的不同(比如是否使用了 VXLAN 等疊加網(wǎng)絡(luò)),你可能需要調(diào)大或者調(diào)小 MTU 的數(shù)值。

第三,網(wǎng)絡(luò)接口的 IP 地址、子網(wǎng)以及 MAC 地址。這些都是保障網(wǎng)絡(luò)功能正常工作所必需的,你需要確保配置正確。

第四,網(wǎng)絡(luò)收發(fā)的字節(jié)數(shù)、包數(shù)、錯(cuò)誤數(shù)以及丟包情況,特別是 TX 和 RX 部分的 errors、dropped、overruns、carrier 以及 collisions 等指標(biāo)不為 0 時(shí),通常表示出現(xiàn)了網(wǎng)絡(luò) I/O 問(wèn)題。其中:

  • errors 表示發(fā)生錯(cuò)誤的數(shù)據(jù)包數(shù),比如校驗(yàn)錯(cuò)誤、幀同步錯(cuò)誤等;
  • dropped 表示丟棄的數(shù)據(jù)包數(shù),即數(shù)據(jù)包已經(jīng)收到了 Ring Buffer,但因?yàn)閮?nèi)存不足等原因丟包;
  • overruns 表示超限數(shù)據(jù)包數(shù),即網(wǎng)絡(luò) I/O 速度過(guò)快,導(dǎo)致 Ring Buffer 中的數(shù)據(jù)包來(lái)不及處理(隊(duì)列滿)而導(dǎo)致的丟包;
  • carrier 表示發(fā)生 carrirer 錯(cuò)誤的數(shù)據(jù)包數(shù),比如雙工模式不匹配、物理電纜出現(xiàn)問(wèn)題等;
  • collisions 表示碰撞數(shù)據(jù)包數(shù)。

套接字信息

ifconfig 和 ip 只顯示了網(wǎng)絡(luò)接口收發(fā)數(shù)據(jù)包的統(tǒng)計(jì)信息,但在實(shí)際的性能問(wèn)題中,網(wǎng)絡(luò)協(xié)議棧中的統(tǒng)計(jì)信息,我們也必須關(guān)注。你可以用 netstat 或者 ss ,來(lái)查看套接字、網(wǎng)絡(luò)棧、網(wǎng)絡(luò)接口以及路由表的信息。

我個(gè)人更推薦,使用 ss 來(lái)查詢網(wǎng)絡(luò)的連接信息,因?yàn)樗?netstat 提供了更好的性能(速度更快)。

比如,你可以執(zhí)行下面的命令,查詢套接字信息:


# head -n 3 表示只顯示前面3行
# -l 表示只顯示監(jiān)聽(tīng)套接字
# -n 表示顯示數(shù)字地址和端口(而不是名字)
# -p 表示顯示進(jìn)程信息
$ netstat -nlp | head -n 3
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      840/systemd-resolve

# -l 表示只顯示監(jiān)聽(tīng)套接字
# -t 表示只顯示 TCP 套接字
# -n 表示顯示數(shù)字地址和端口(而不是名字)
# -p 表示顯示進(jìn)程信息
$ ss -ltnp | head -n 3
State    Recv-Q    Send-Q        Local Address:Port        Peer Address:Port
LISTEN   0         128           127.0.0.53%lo:53               0.0.0.0:*        users:(("systemd-resolve",pid=840,fd=13))
LISTEN   0         128                 0.0.0.0:22               0.0.0.0:*        users:(("sshd",pid=1459,fd=3))

netstat 和 ss 的輸出也是類似的,都展示了套接字的狀態(tài)、接收隊(duì)列、發(fā)送隊(duì)列、本地地址、遠(yuǎn)端地址、進(jìn)程 PID 和進(jìn)程名稱等。

其中,接收隊(duì)列(Recv-Q)和發(fā)送隊(duì)列(Send-Q)需要你特別關(guān)注,它們通常應(yīng)該是 0。當(dāng)你發(fā)現(xiàn)它們不是 0 時(shí),說(shuō)明有網(wǎng)絡(luò)包的堆積發(fā)生。當(dāng)然還要注意,在不同套接字狀態(tài)下,它們的含義不同。

當(dāng)套接字處于連接狀態(tài)(Established)時(shí),

  • Recv-Q 表示套接字緩沖還沒(méi)有被應(yīng)用程序取走的字節(jié)數(shù)(即接收隊(duì)列長(zhǎng)度)。
  • 而 Send-Q 表示還沒(méi)有被遠(yuǎn)端主機(jī)確認(rèn)的字節(jié)數(shù)(即發(fā)送隊(duì)列長(zhǎng)度)。

當(dāng)套接字處于監(jiān)聽(tīng)狀態(tài)(Listening)時(shí),

  • Recv-Q 表示全連接隊(duì)列的長(zhǎng)度。
  • 而 Send-Q 表示全連接隊(duì)列的最大長(zhǎng)度。

所謂全連接,是指服務(wù)器收到了客戶端的 ACK,完成了 TCP 三次握手,然后就會(huì)把這個(gè)連接挪到全連接隊(duì)列中。這些全連接中的套接字,還需要被 accept() 系統(tǒng)調(diào)用取走,服務(wù)器才可以開(kāi)始真正處理客戶端的請(qǐng)求。

與全連接隊(duì)列相對(duì)應(yīng)的,還有一個(gè)半連接隊(duì)列。所謂半連接是指還沒(méi)有完成 TCP 三次握手的連接,連接只進(jìn)行了一半。服務(wù)器收到了客戶端的 SYN 包后,就會(huì)把這個(gè)連接放到半連接隊(duì)列中,然后再向客戶端發(fā)送 SYN+ACK 包。

協(xié)議棧統(tǒng)計(jì)信息

類似的,使用 netstat 或 ss ,也可以查看協(xié)議棧的信息:


$ netstat -s
...
Tcp:
    3244906 active connection openings
    23143 passive connection openings
    115732 failed connection attempts
    2964 connection resets received
    1 connections established
    13025010 segments received
    17606946 segments sent out
    44438 segments retransmitted
    42 bad segments received
    5315 resets sent
    InCsumErrors: 42
...

$ ss -s
Total: 186 (kernel 1446)
TCP:   4 (estab 1, closed 0, orphaned 0, synrecv 0, timewait 0/0), ports 0

Transport Total     IP        IPv6
*    1446      -         -
RAW    2         1         1
UDP    2         2         0
TCP    4         3         1
...

這些協(xié)議棧的統(tǒng)計(jì)信息都很直觀。ss 只顯示已經(jīng)連接、關(guān)閉、孤兒套接字等簡(jiǎn)要統(tǒng)計(jì),而 netstat 則提供的是更詳細(xì)的網(wǎng)絡(luò)協(xié)議棧信息。

比如,上面 netstat 的輸出示例,就展示了 TCP 協(xié)議的主動(dòng)連接、被動(dòng)連接、失敗重試、發(fā)送和接收的分段數(shù)量等各種信息。

網(wǎng)絡(luò)吞吐和 PPS

接下來(lái),我們?cè)賮?lái)看看,如何查看系統(tǒng)當(dāng)前的網(wǎng)絡(luò)吞吐量和 PPS。在這里,我推薦使用我們的老朋友 sar,在前面的 CPU、內(nèi)存和 I/O 模塊中,我們已經(jīng)多次用到它。

給 sar 增加 -n 參數(shù)就可以查看網(wǎng)絡(luò)的統(tǒng)計(jì)信息,比如網(wǎng)絡(luò)接口(DEV)、網(wǎng)絡(luò)接口錯(cuò)誤(EDEV)、TCP、UDP、ICMP 等等。執(zhí)行下面的命令,你就可以得到網(wǎng)絡(luò)接口統(tǒng)計(jì)信息:


# 數(shù)字1表示每隔1秒輸出一組數(shù)據(jù)
$ sar -n DEV 1
Linux 4.15.0-1035-azure (ubuntu)   01/06/19   _x86_64_  (2 CPU)

13:21:40        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
13:21:41         eth0     18.00     20.00      5.79      4.25      0.00      0.00      0.00      0.00
13:21:41      docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
13:21:41           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

這兒輸出的指標(biāo)比較多,我來(lái)簡(jiǎn)單解釋下它們的含義。

  • rxpck/s 和 txpck/s 分別是接收和發(fā)送的 PPS,單位為包 / 秒
  • rxkB/s 和 txkB/s 分別是接收和發(fā)送的吞吐量,單位是 KB/ 秒
  • rxcmp/s 和 txcmp/s 分別是接收和發(fā)送的壓縮數(shù)據(jù)包數(shù),單位是包 / 秒
  • %ifutil 是網(wǎng)絡(luò)接口的使用率,即半雙工模式下為 (rxkB/s+txkB/s)/Bandwidth,而全雙工模式下為 max(rxkB/s, txkB/s)/Bandwidth

其中,Bandwidth 可以用 ethtool 來(lái)查詢,它的單位通常是 Gb/s 或者 Mb/s,不過(guò)注意這里小寫字母 b ,表示比特而不是字節(jié)。我們通常提到的千兆網(wǎng)卡、萬(wàn)兆網(wǎng)卡等,單位也都是比特。如下你可以看到,我的 eth0 網(wǎng)卡就是一個(gè)千兆網(wǎng)卡:

其中,Bandwidth 可以用 ethtool 來(lái)查詢,它的單位通常是 Gb/s 或者 Mb/s,不過(guò)注意這里小寫字母 b ,表示比特而不是字節(jié)。我們通常提到的千兆網(wǎng)卡、萬(wàn)兆網(wǎng)卡等,單位也都是比特。如下你可以看到,我的 eth0 網(wǎng)卡就是一個(gè)千兆網(wǎng)卡:

$ ethtool eth0 | grep Speed
  Speed: 1000Mb/s

小結(jié)

我們通常使用帶寬、吞吐量、延時(shí)等指標(biāo),來(lái)衡量網(wǎng)絡(luò)的性能;相應(yīng)的,你可以用 ifconfig、netstat、ss、sar、ping 等工具,來(lái)查看這些網(wǎng)絡(luò)的性能指標(biāo)。

小狗同學(xué)問(wèn)到: 老師,您好 ss —lntp 這個(gè) 當(dāng)session處于listening中 rec-q 確定是 syn的backlog嗎?
A: Recv-Q為全連接隊(duì)列當(dāng)前使用了多少。 中文資料里這個(gè)問(wèn)題講得最明白的文章:https://mp.weixin.qq.com/s/yH3PzGEFopbpA-jw4MythQ

看了源碼發(fā)現(xiàn),這個(gè)地方講的有問(wèn)題.關(guān)于ss輸出中l(wèi)isten狀態(tài)套接字的Recv-Q表示全連接隊(duì)列當(dāng)前使用了多少,也就是全連接隊(duì)列的當(dāng)前長(zhǎng)度,而Send-Q表示全連接隊(duì)列的最大長(zhǎng)度

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容