Linux網絡包接收過程的監控與調優

上一篇文章中《圖解Linux網絡包接收過程》,咱們梳理了在Linux系統下一個數據包被接收的整個過程。Linux內核對網絡包的接收過程大體能夠分爲接收到RingBuffer、硬中斷處理、ksoftirqd軟中斷處理幾個過程。其中在ksoftirqd軟中斷處理中,把數據包從RingBuffer中摘下來,送到協議棧的處理,再以後送到用戶進程socket的接收隊列中。服務器

理解了Linux工做原理以後,還有更重要的兩件事情。第一是動手監控,會實際查看網絡包接收的總體狀況。第二是調優,當你的服務器有問題的時候,你能找到瓶頸所在,並會利用內核開放的參數進行調節。網絡

先說幾個工具

在正式內容開始以前,咱們先來了解幾個Linux下監控網卡時可用的工具。數據結構

ethtool

首先第一個工具就是咱們在上文中提到的ethtool,它用來查看和設置網卡參數。這個工具其實自己只是提供幾個通用接口,真正的實現是都是在網卡驅動中的。正由於該工具是由驅動直接實現的,因此我的以爲它最重要。socket

該命令比較複雜,咱們選幾個今天能用到的說ide

  • -i 顯示網卡驅動的信息,如驅動的名稱、版本等
  • -S 查看網卡收發包的統計狀況
  • -g/-G 查看或者修改RingBuffer的大小
  • -l/-L 查看或者修改網卡隊列數
  • -c/-C 查看或者修改硬中斷合併策略

實際查看一下網卡驅動:函數

# ethtool -i eth0
driver: ixgbe
......

這裏看到個人機器上網卡驅動程序是ixgbe。有了驅動名稱,就能夠在源碼中找到對應的代碼了。對於ixgbe來講,其驅動的源代碼位於drivers/net/ethernet/intel/ixgbe目錄下。ixgbe_ethtool.c下都是實現的供ethtool使用的相關函數,若是ethtool哪裏有搞不明白的,就能夠經過這種方式查找到源碼來讀。另外咱們前文《圖解Linux網絡包接收過程》裏提到的NAPI收包時的poll回調函數,啓動網卡時的open函數都是在這裏實現的。工具

ifconfig

網絡管理工具ifconfig不僅是能夠爲網卡配置ip,啓動或者禁用網卡,也包含了一些網卡的統計信息。優化

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.162.42.51  netmask 255.255.248.0  broadcast 10.162.47.255
        inet6 fe80::6e0b:84ff:fed5:88d1  prefixlen 64  scopeid 0x20<link>
        ether 6c:0b:84:d5:88:d1  txqueuelen 1000  (Ethernet)
        RX packets 2953454  bytes 414212810 (395.0 MiB)
        RX errors 0  dropped 4636605  overruns 0  frame 0
        TX packets 127887  bytes 82943405 (79.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • RX packets:接收的總包數
  • RX bytes:接收的字節數
  • RX errors:表示總的收包的錯誤數量
  • RX dropped:數據包已經進入了 Ring Buffer,可是因爲其它緣由致使的丟包
  • RX overruns:表示了 fifo 的 overruns,這是因爲 Ring Buffer不足致使的丟包

僞文件系統/proc

Linux 內核提供了 /proc 僞文件系統,經過/proc能夠查看內核內部數據結構、改變內核設置。咱們先跑一下題,看一下這個僞文件系統裏都有啥:ui

  • /proc/sys目錄能夠查看或修改內核參數
  • /proc/cpuinfo能夠查看CPU信息
  • /proc/meminfo能夠查看內存信息
  • /proc/interrupts統計全部的硬中斷
  • /proc/softirqs統計的全部的軟中斷信息
  • /proc/slabinfo統計了內核數據結構的slab內存使用狀況
  • /proc/net/dev能夠看到一些網卡統計數據

詳細聊下僞文件/proc/net/dev,經過它能夠看到內核中對網卡的一些相關統計。包含了如下信息:.net

  • bytes: 發送或接收的數據的總字節數
  • packets: 接口發送或接收的數據包總數
  • errs: 由設備驅動程序檢測到的發送或接收錯誤的總數
  • drop: 設備驅動程序丟棄的數據包總數
  • fifo: FIFO緩衝區錯誤的數量
  • frame: The number of packet framing errors.(分組幀錯誤的數量)
  • colls: 接口上檢測到的衝突數

因此,僞文件/proc/net/dev也能夠做爲咱們查看網卡工做統計數據的工具之一。

僞文件系統sysfs

sysfs和/proc相似,也是一個僞文件系統,可是比proc更新,結構更清晰。 其中的/sys/class/net/eth0/statistics/也包含了網卡的統計信息。

# cd /sys/class/net/eth0/statistics/ 
# grep . * | grep tx
tx_aborted_errors:0
tx_bytes:170699510
tx_carrier_errors:0
tx_compressed:0
tx_dropped:0
tx_errors:0
tx_fifo_errors:0
tx_heartbeat_errors:0
tx_packets:262330
tx_window_errors:0

好了,簡單瞭解過這幾個工具之後,讓咱們正式開始今天的行程。

RingBuffer監控與調優

前面咱們看到,當網線中的數據幀到達網卡後,第一站就是RingBuffer(網卡經過DMA機制將數據幀送到RingBuffer中)。所以咱們第一個要監控和調優的就是網卡的RingBuffer,咱們使用ethtool來來查看一下Ringbuffer。

# ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX:     4096
RX Mini:    0
RX Jumbo:   0
TX:     4096
Current hardware settings:
RX:     512
RX Mini:    0
RX Jumbo:   0
TX:     512

這裏看到我手頭的網卡設置RingBuffer最大容許設置到4096,目前的實際設置是512。

這裏有一個小細節,ethtool查看到的是實際是Rx bd的大小。Rx bd位於網卡中,至關於一個指針。RingBuffer在內存中,Rx bd指向RingBuffer。Rx bd和RingBuffer中的元素是一一對應的關係。在網卡啓動的時候,內核會爲網卡的Rx bd在內存中分配RingBuffer,並設置好對應關係。

在Linux的整個網絡棧中,RingBuffer起到一個任務的收發中轉站的角色。對於接收過程來說,網卡負責往RingBuffer中寫入收到的數據幀,ksoftirqd內核線程負責從中取走處理。只要ksoftirqd線程工做的足夠快,RingBuffer這個中轉站就不會出現問題。可是咱們設想一下,假如某一時刻,瞬間來了特別多的包,而ksoftirqd處理不過來了,會發生什麼?這時RingBuffer可能瞬間就被填滿了,後面再來的包網卡直接就會丟棄,不作任何處理!

那咱們怎麼樣能看一下,咱們的服務器上是否有由於這個緣由致使的丟包呢? 前面咱們介紹的四個工具均可以查看這個丟包統計,拿ethtool來舉例:

# ethtool -S eth0
......
rx_fifo_errors: 0
tx_fifo_errors: 0

rx_fifo_errors若是不爲0的話(在 ifconfig 中體現爲 overruns 指標增加),就表示有包由於RingBuffer裝不下而被丟棄了。那麼怎麼解決這個問題呢?很天然首先咱們想到的是,加大RingBuffer這個「中轉倉庫」的大小。經過ethtool就能夠修改。

# ethtool -G eth1 rx 4096 tx 4096

這樣網卡會被分配更大一點的」中轉站「,能夠解決偶發的瞬時的丟包。不過這種方法有個小反作用,那就是排隊的包過多會增長處理網絡包的延時。因此另一種解決思考更好,。那就是讓內核處理網絡包的速度更快一些,而不是讓網絡包傻傻地在RingBuffer中排隊。怎麼加快內核消費RingBuffer中任務的速度呢,彆着急,咱們繼續往下看...

硬中斷監控與調優

在數據被接收到RingBuffer以後,下一個執行就是就是硬中斷的發起。咱們先來查看硬中斷,而後再聊下怎麼優化。

監控

硬中斷的狀況能夠經過內核提供的僞文件/proc/interrupts來進行查看。

$ cat  /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
  0:         34          0          0          0   IO-APIC-edge      timer
 ......
 27:        351          0          0 1109986815   PCI-MSI-edge      virtio1-input.0
 28:       2571          0          0          0   PCI-MSI-edge      virtio1-output.0
 29:          0          0          0          0   PCI-MSI-edge      virtio2-config
 30:    4233459 1986139461     244872     474097   PCI-MSI-edge      virtio2-input.0
 31:          3          0          2          0   PCI-MSI-edge      virtio2-output.0

上述結果是我手頭的一臺虛機的輸出結果。上面包含了很是豐富的信息,讓咱們一一道來:

  • 網卡的輸入隊列virtio1-input.0的中斷號是27
  • 27號中斷都是由CPU3來處理的
  • 總的中斷次數是1109986815。

這裏有兩個細節咱們須要關注一下。
1)爲何輸入隊列的中斷都在CPU3上呢?
這是由於內核的一個配置,在僞文件系統中能夠查看到。

#cat /proc/irq/27/smp_affinity
8

smp_affinity裏是CPU的親和性的綁定,8是二進制的1000,第4位爲1,表明的就是第4個CPU核心-CPU3。

2)對於收包來過程來說,硬中斷的總次數表示的是Linux收包總數嗎?
不是,硬件中斷次數不表明總的網絡包數。第一網卡能夠設置中斷合併,多個網絡幀能夠只發起一次中斷。第二NAPI 運行的時候會關閉硬中斷,經過poll來收包。

多隊列網卡調優

如今的主流網卡基本上都是支持多隊列的,咱們能夠經過將不一樣的隊列分給不一樣的CPU核心來處理,從而加快Linux內核處理網絡包的速度。這是最爲有用的一個優化手段。

每個隊列都有一箇中斷號,能夠獨立向某個CPU核心發起硬中斷請求,讓CPU來poll包。經過將接收進來的包被放到不一樣的內存隊列裏,多個CPU就能夠同時分別向不一樣的隊列發起消費了。這個特性叫作RSS(Receive Side Scaling,接收端擴展)。經過ethtool工具能夠查看網卡的隊列狀況。

# ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:		0
TX:		0
Other:		1
Combined:	63
Current hardware settings:
RX:		0
TX:		0
Other:		1
Combined:	8

上述結果表示當前網卡支持的最大隊列數是63,當前開啓的隊列數是8。對於這個配置來說,最多同時能夠有8個核心來參與網絡收包。若是你想提升內核收包的能力,直接簡單加大隊列數就能夠了,這比加大RingBuffer更爲有用。由於加大RingBuffer只是給個更大的空間讓網絡幀能繼續排隊,而加大隊列數則能讓包更早地被內核處理。ethtool修改隊列數量方法以下:

#ethtool -L eth0 combined 32

咱們前文說過,硬中斷髮生在哪個核上,它發出的軟中斷就由哪一個核來處理。全部經過加大網卡隊列數,這樣硬中斷工做、軟中斷工做都會有更多的核心參與進來。

每個隊列都有一箇中斷號,每個中斷號都是綁定在一個特定的CPU上的。若是你不滿意某一箇中斷的CPU綁定,能夠經過修改/proc/irq/{中斷號}/smp_affinity來實現。

通常處理到這裏,網絡包的接收就沒有大問題了。但若是你有更高的追求,或者是說你並無更多的CPU核心能夠參與進來了,那怎麼辦?放心,咱們也還有方法提升單核的處理網絡包的接收速度。

硬中斷合併

先來說一個實際中的例子,假如你是一位開發同窗,和你對口的產品經理一天有10個小需求須要讓你幫忙來處理。她對你有兩種中斷方式:

  • 第一種:產品經理想到一個需求,就過來找你,和你描述需求細節,而後讓你幫你來改
  • 第二種:產品經理想到需求後,不來打擾你,等攢夠5個來找你一次,你集中處理

咱們如今不考慮及時性,只考慮你的工做總體效率,你以爲那種方案下你的工做效率會高呢?或者換句話說,你更喜歡哪種工做狀態呢?很明顯,只要你是一個正常的開發,都會以爲第二種方案更好。對人腦來說,頻繁的中斷會打亂你的計劃,你腦子裏剛纔剛想到一半技術方案可能也就廢了。當產品經理走了之後,你再想撿起來剛被中斷之的工做的時候,極可能得花點時間回憶一下子才能繼續工做。

對於CPU來說也是同樣,CPU要作一件新的事情以前,要加載該進程的地址空間,load進程代碼,讀取進程數據,各級別cache要慢慢熱身。所以若是能適當下降中斷的頻率,多攢幾個包一塊兒發出中斷,對提高CPU的工做效率是有幫助的。因此,網卡容許咱們對硬中斷進行合併。

如今咱們來看一下網卡的硬中斷合併配置。

# ethtool -c eth0
Coalesce parameters for eth0:
Adaptive RX: off  TX: off
......

rx-usecs: 1
rx-frames: 0
rx-usecs-irq: 0
rx-frames-irq: 0
......

咱們來講一下上述結果的大體含義

  • Adaptive RX: 自適應中斷合併,網卡驅動本身判斷啥時候該合併啥時候不合並
  • rx-usecs: 當過這麼長時間事後,一個RX interrupt就會被產生
  • rx-frames:當累計接收到這麼多個幀後,一個RX interrupt就會被產生

若是你想好了修改其中的某一個參數了的話,直接使用ethtool -C就能夠,例如:

ethtool -C eth0 adaptive-rx on

不過須要注意的是,減小中斷數量雖然能使得Linux總體吞吐更高,不過一些包的延遲也會增大,因此用的時候得適當注意。

軟中斷監控與調優

在硬中斷以後,再接下來的處理過程就是ksoftirqd內核線程中處理的軟中斷了。以前咱們說過,軟中斷和它對應的硬中斷是在同一個核心上處理的。 所以,前面硬中斷分散到多核上處理的時候,軟中斷的優化其實也就跟着作了,也會被多核處理。不過軟中斷也還有本身的可優化選項。

監控

軟中斷的信息能夠從 /proc/softirqs 讀取:

$ cat /proc/softirqs
                    CPU0       CPU1       CPU2       CPU3
          HI:          0          2          2          0
       TIMER:  704301348 1013086839  831487473 2202821058
      NET_TX:      33628      31329      32891     105243
      NET_RX:  418082154 2418421545  429443219 1504510793
       BLOCK:         37          0          0   25728280
BLOCK_IOPOLL:          0          0          0          0
     TASKLET:     271783     273780     276790     341003
       SCHED: 1544746947 1374552718 1287098690 2221303707
     HRTIMER:          0          0          0          0
         RCU: 3200539884 3336543147 3228730912 3584743459

軟中斷budget調整

不知道你有沒有據說過番茄工做法,它的大體意思就是你要有一整段的不被打擾的時間,集中精力處理某一項做業。這一整段時間時長被建議是25分鐘。
對於咱們的Linux的處理軟中斷的ksoftirqd來講,它也和番茄工做法思路相似。一旦它被硬中斷觸發開始了工做,它會集中精力處理一波兒網絡包(毫不只是1個),而後再去作別的事情。

咱們說的處理一波兒是多少呢,策略略複雜。咱們只說其中一個比較容易理解的,那就是net.core.netdev_budget內核參數。

#sysctl -a | grep 
net.core.netdev_budget = 300

這個的意思說的是,ksoftirqd一次最多處理300個包,處理夠了就會把CPU主動讓出來,以便Linux上其它的任務能夠獲得處理。 那麼假如說,咱們如今就是想提升內核處理網絡包的效率。那就可讓ksoftirqd進程多幹一下子網絡包的接收,再讓出CPU。至於怎麼提升,直接修改不這個參數的值就行了。

#sysctl -w net.core.netdev_budget=600

若是要保證重啓仍然生效,須要將這個配置寫到/etc/sysctl.conf

軟中斷GRO合併

GRO和硬中斷合併的思想很相似,不過階段不一樣。硬中斷合併是在中斷髮起以前,而GRO已經到了軟中斷上下文中了。

若是應用中是大文件的傳輸,大部分包都是一段數據,不用GRO的話,會每次都將一個小包傳送到協議棧(IP接收函數、TCP接收)函數中進行處理。開啓GRO的話,Linux就會智能進行包的合併,以後將一個大包傳給協議處理函數。這樣CPU的效率也是就提升了。

ethtool -k eth0 | grep generic-receive-offload
generic-receive-offload: on

若是你的網卡驅動沒有打開GRO的話,能夠經過以下方式打開。

# ethtool -K eth0 gro on

GRO說的僅僅只是包的接收階段的優化方式,對於發送來講是GSO。

總結

在網絡技術這一領域裏,有太多的知識內容都停留在理論階段了。你可能以爲你的網絡學的倒背如流了,但是當你的線上服務出現問題的時候,你仍是不知道該怎麼排查,怎麼優化。這就是由於只懂了理論,而不清楚Linux是經過哪些內核機制將網絡技術落地的,各個內核組件之間怎麼配合,每一個組件有哪些參數能夠作調整。咱們用兩篇文章詳細討論了Linux網絡包的接收過程,以及這個過程當中的一些統計數據如何查看,如何調優。相信消化完這兩篇文章以後,你的網絡的理解直接能提高1個Level,你對線上服務的把控能力也會更加如魚得水。


file


開發內功修煉之硬盤篇專輯:


個人公衆號是「開發內功修煉」,在這裏我不是單純介紹技術理論,也不僅介紹實踐經驗。而是把理論與實踐結合起來,用實踐加深對理論的理解、用理論提升你的技術實踐能力。歡迎你來關注個人公衆號,也請分享給你的好友~~~

相關文章
相關標籤/搜索