頻寬、延時、吞吐率、PPS 這些都是啥?
Linux 網路協議棧是根據 TCP/IP 模型來實現的,TCP/IP 模型由應用層、傳輸層、網路層和網路介面層,共四層組成,每一層都有各自的職責。
應用程式要傳送資料包時,通常是通過 socket 介面,於是就會發生系統呼叫,把應用層的資料拷貝到核心裡的 socket 層,接著由網路協議棧從上到下逐層處理後,最後才會送到網絡卡傳送出去。
而對於接收網路包時,同樣也要經過網路協議逐層處理,不過處理的方向與傳送資料時是相反的,也就是從下到上的逐層處理,最後才送到應用程式。
網路的速度往往跟使用者體驗是掛鉤的,那我們又該用什麼指標來衡量 Linux 的網路效能呢?以及如何分析網路問題呢?
這次,我們就來說這些。
效能指標有哪些?
通常是以 4 個指標來衡量網路的效能,分別是頻寬、延時、吞吐率、PPS(Packet Per Second),它們表示的意義如下:
- 頻寬,表示鏈路的最大傳輸速率,單位是 b/s (位元 / 秒),頻寬越大,其傳輸能力就越強。
- 延時,表示請求資料包傳送後,收到對端響應,所需要的時間延遲。不同的場景有著不同的含義,比如可以表示建立 TCP 連線所需的時間延遲,或一個數據包往返所需的時間延遲。
- 吞吐率,表示單位時間內成功傳輸的資料量,單位是 b/s(位元 / 秒)或者 B/s(位元組 / 秒),吞吐受頻寬限制,頻寬越大,吞吐率的上限才可能越高。
- PPS,全稱是 Packet Per Second(包 / 秒),表示以網路包為單位的傳輸速率,一般用來評估系統對於網路的轉發能力。
當然,除了以上這四種基本的指標,還有一些其他常用的效能指標,比如:
- 網路的可用性,表示網路能否正常通訊;
- 併發連線數,表示 TCP 連線數量;
- 丟包率,表示所丟失資料包數量佔所傳送資料組的比率;
- 重傳率,表示重傳網路包的比例;
你可能會問了,如何觀測這些效能指標呢?不急,繼續往下看。
網路配置如何看?
要想知道網路的配置和狀態,我們可以使用 ifconfig
或者 ip
命令來檢視。
這兩個命令功能都差不多,不過它們屬於不同的軟體包,ifconfig
屬於 net-tools
軟體包,ip
屬於 iproute2
軟體包,我的印象中 net-tools
軟體包沒有人繼續維護了,而 iproute2
ip
工具。
學以致用,那就來使用這兩個命令,來檢視網口 eth0
的配置等資訊:
雖然這兩個命令輸出的格式不盡相同,但是輸出的內容基本相同,比如都包含了 IP 地址、子網掩碼、MAC 地址、閘道器地址、MTU 大小、網口的狀態以及網路包收發的統計資訊,下面就來說說這些資訊,它們都與網路效能有一定的關係。
第一,網口的連線狀態標誌。其實也就是表示對應的網口是否連線到交換機或路由器等裝置,如果 ifconfig
輸出中看到有 RUNNING
,或者 ip
輸出中有 LOWER_UP
,則說明物理網路是連通的,如果看不到,則表示網口沒有接網線。
第二,MTU 大小。預設值是 1500
位元組,其作用主要是限制網路包的大小,如果 IP 層有一個數據報要傳,而且資料幀的長度比鏈路層的 MTU 還大,那麼 IP 層就需要進行分片,即把資料報分成乾片,這樣每一片就都小於 MTU。事實上,每個網路的鏈路層 MTU 可能會不一樣,所以你可能需要調大或者調小 MTU 的數值。
第三,網口的 IP 地址、子網掩碼、MAC 地址、閘道器地址。這些資訊必須要配置正確,網路功能才能正常工作。
第四,網路包收發的統計資訊。通常有網路收發的位元組數、包數、錯誤數以及丟包情況的資訊,如果 TX
(傳送) 和 RX
(接收) 部分中 errors、dropped、overruns、carrier 以及 collisions 等指標不為 0 時,則說明網路傳送或者接收出問題了,這些出錯統計資訊的指標意義如下:
- errors 表示發生錯誤的資料包數,比如校驗錯誤、幀同步錯誤等;
- dropped 表示丟棄的資料包數,即資料包已經收到了 Ring Buffer(這個緩衝區是在核心記憶體中,更具體一點是在網絡卡驅動程式裡),但因為系統記憶體不足等原因而發生的丟包;
- overruns 表示超限資料包數,即網路接收/傳送速度過快,導致 Ring Buffer 中的資料包來不及處理,而導致的丟包,因為過多的資料包擠壓在 Ring Buffer,這樣 Ring Buffer 很容易就溢位了;
- carrier 表示發生 carrirer 錯誤的資料包數,比如雙工模式不匹配、物理電纜出現問題等;
- collisions 表示衝突、碰撞資料包數;
ifconfig
和 ip
命令只顯示的是網口的配置以及收發資料包的統計資訊,而看不到協議棧裡的資訊,那接下來就來看看如何檢視協議棧裡的資訊。
socket 資訊如何檢視?
我們可以使用 netstat
或者 ss
,這兩個命令檢視 socket、網路協議棧、網口以及路由表的資訊。
雖然 netstat
與 ss
命令檢視的資訊都差不多,但是如果在生產環境中要檢視這類資訊的時候,儘量不要使用 netstat
命令,因為它的效能不好,在系統比較繁忙的情況下,如果頻繁使用 netstat
命令則會對效能的開銷雪上加霜,所以更推薦你使用效能更好的 ss
命令。
從下面這張圖,你可以看到這兩個命令的輸出內容:
可以發現,輸出的內容都差不多, 比如都包含了 socket 的狀態(State)、接收佇列(Recv-Q)、傳送佇列(Send-Q)、本地地址(Local Address)、遠端地址(Foreign Address)、程序 PID 和程序名稱(PID/Program name)等。
接收佇列(Recv-Q)和傳送佇列(Send-Q)比較特殊,在不同的 socket 狀態。它們表示的含義是不同的。
當 socket 狀態處於 Established
時:
- Recv-Q 表示 socket 緩衝區中還沒有被應用程式讀取的位元組數;
- Send-Q 表示 socket 緩衝區中還沒有被遠端主機確認的位元組數;
而當 socket 狀態處於 Listen
時:
- Recv-Q 表示全連線佇列的長度;
- Send-Q 表示全連線佇列的最大長度;
在 TCP 三次握手過程中,當伺服器收到客戶端的 SYN 包後,核心會把該連線儲存到半連線佇列,然後再向客戶端傳送 SYN+ACK 包,接著客戶端會返回 ACK,服務端收到第三次握手的 ACK 後,核心會把連線從半連線佇列移除,然後建立新的完全的連線,並將其增加到全連線佇列 ,等待程序呼叫 accept()
函式時把連線取出來。
也就說,全連線佇列指的是伺服器與客戶端完了 TCP 三次握手後,還沒有被 accept()
系統呼叫取走連線的佇列。
那對於協議棧的統計資訊,依然還是使用 netstat
或 ss
,它們檢視統計資訊的命令如下:
ss
命令輸出的統計資訊相比 netsat
比較少,ss
只顯示已經連線(estab)、關閉(closed)、孤兒(orphaned) socket 等簡要統計。
而 netstat
則有更詳細的網路協議棧資訊,比如上面顯示了 TCP 協議的主動連線(active connections openings)、被動連線(passive connection openings)、失敗重試(failed connection attempts)、傳送(segments send out)和接收(segments received)的分段數量等各種資訊。
網路吞吐率和 PPS 如何檢視?
可以使用 sar
命令當前網路的吞吐率和 PPS,用法是給 sar
增加 -n
引數就可以檢視網路的統計資訊,比如
- sar -n DEV,顯示網口的統計資料;
- sar -n EDEV,顯示關於網路錯誤的統計資料;
- sar -n TCP,顯示 TCP 的統計資料
比如,我通過 sar
命令獲取了網口的統計資訊:
它們的含義:
rxpck/s
和txpck/s
分別是接收和傳送的 PPS,單位為包 / 秒。rxkB/s
和txkB/s
分別是接收和傳送的吞吐率,單位是 KB/ 秒。rxcmp/s
和txcmp/s
分別是接收和傳送的壓縮資料包數,單位是包 / 秒。
對於頻寬,我們可以使用 ethtool
命令來查詢,它的單位通常是 Gb/s
或者 Mb/s
,不過注意這裡小寫字母 b
,表示位元而不是位元組。我們通常提到的千兆網絡卡、萬兆網絡卡等,單位也都是位元(bit)。如下你可以看到, eth0 網絡卡就是一個千兆網絡卡:
$ ethtool eth0 | grep Speed
Speed: 1000Mb/s
連通性和延時如何檢視?
要測試本機與遠端主機的連通性和延時,通常是使用 ping
命令,它是基於 ICMP 協議的,工作在網路層。
比如,如果要測試本機到 192.168.12.20
IP 地址的連通性和延時:
顯示的內容主要包含 icmp_seq
(ICMP 序列號)、TTL
(生存時間,或者跳數)以及 time
(往返延時),而且最後會彙總本次測試的情況,如果網路沒有丟包,packet loss
的百分比就是 0。
不過,需要注意的是,ping
不通伺服器並不代表 HTTP 請求也不通,因為有的伺服器的防火牆是會禁用 ICMP 協議的。
推薦閱讀
你不好奇 Linux 是如何收發網路包的?
TCP 半連線佇列和全連線佇列滿了會發生什麼?又該如何應對?
哈嘍,我是小林,就愛圖解計算機基礎,如果覺得文章對你有幫助,歡迎分享給你的朋友,也給小林點個「贊 + 收藏」,這對小林非常重要,謝謝你們,給各位小姐姐小哥哥們抱拳了,我們下次見!