如何透過調校伺服器網卡佇列數量修復封包遺失問題

封包遺失是令人頭痛的網路問題。一個經常被忽略的原因,是伺服器網卡佇列數量配置不當而導致封包遺失。本文將說明一套系統化的處理流程。你可以先執行基礎測試,例如使用 ping 測量封包遺失率,使用 iperf 模擬流量。這能幫助你建立基準參考。接著,你需要檢查硬體封包遺失計數器,並將其與佇列數量進行比對,從而定位問題。然後,你要確定適合網卡調校的最佳佇列數量,使其與 CPU 核心數和實際工作負載相匹配。之後再調整佇列數量,並驗證修復效果。如果封包遺失仍然存在,就繼續調校作業系統網路堆疊和網卡設定,例如增大環形緩衝區大小以及設定 irq 親和性。完成這些調整的核心工具是 ethtool。每一步都應包含驗證動作。你要在進入下一步之前先完成驗證。這種方法能夠直接定位根因,並有效率地解決問題。
診斷由佇列數量配置不當引起的封包遺失
在你修改任何設定之前,必須先證明問題的根源確實是佇列數量。伺服器網卡佇列數量配置不當導致封包遺失時,通常會表現出明顯症狀。你的任務就是找出這些症狀,並排除其他可能原因。
執行基礎封包遺失測試
先從一個簡單的連通性測試開始。在用戶端機器上對伺服器執行 ping。傳送大量資料封包,至少幾千個,這樣結果才有統計意義。觀察封包遺失百分比。健康的連線在輕負載下應顯示零遺失。如果在閒置網路中仍持續出現封包遺失,通常就表示存在設定問題。
接下來,使用 iperf3 產生真實流量。在目標機器上執行伺服端,在對端主機上執行用戶端,並持續壓測一段時間。觀察報告中的封包遺失率和重傳次數。如果封包遺失只在負載上升後出現,那麼佇列數量就很可能是關鍵嫌疑點。輕流量只會使用少量佇列,而重流量會擴散到所有佇列。佇列數量與 CPU 核心數不匹配的問題,往往正是在這種情況下暴露出來。
請重複測試多次。如果每次執行都能觀察到間歇性封包遺失,那麼你就得到了一個可靠的模式。單次異常結果也許只是雜訊。
使用 ethtool -S 檢查封包遺失計數器
現在開始查看硬體本身。對你的網路介面執行 ethtool -S。該指令會輸出驅動層級的所有計數器。你需要重點關注兩個值:rx_dropped 和 tx_dropped。rx 表示網卡已經接收到了資料封包,但未能成功交給核心;tx 表示網卡未能成功傳送資料封包。
先記錄下這些數值。等待一小段時間後,再次執行該指令,並比較兩次結果。如果計數器在閒置期間仍持續上升,就表示確實存在問題;如果在高負載下計數器仍保持不變,則表示這一項基本正常。
接著,把封包遺失情況與目前佇列數量進行比對。使用 ethtool -l 查看佇列數量。如果你發現佇列很多,而 CPU 核心卻很少,那麼核心就無法及時處理所有佇列。中斷會堆積,資料封包等待時間過長,最終被丟棄。下表展示了如何判斷這種模式。
| 現象 | 可能原因 |
|---|---|
| rx_dropped 持續上升,且佇列數超過 CPU 核心數 | 佇列過多,超出可用核心處理能力 |
| tx_dropped 在高負載下上升 | 佇列過小或環形緩衝區耗盡 |
| 兩個計數器都保持不變,但仍存在封包遺失 | 需要檢查網卡之外的問題,例如線材和交換器 |
還有一個額外檢查會很有幫助。執行 ethtool -S,並 grep 每佇列的封包遺失欄位。許多驅動會依佇列回報封包遺失情況。如果封包遺失集中在少數幾個佇列上,就表示流量分布並不均衡。這通常指向 IRQ 親和性問題,後文會繼續處理。
到這裡,你已經掌握了證據。如果封包遺失計數器持續上升,同時佇列數量與 CPU 配置不匹配,那麼基本可以確認診斷結果。接下來進入下一步,計算合適的佇列數量。
確定網卡調校的最佳佇列數量
讓佇列數量匹配 CPU 核心數
網卡調校的第一條原則很簡單:佇列數量要與負責處理網路中斷的 CPU 核心數匹配。每個佇列都需要自己的中斷向量。如果你建立的佇列多於核心數量,核心就無法及時處理所有佇列。資料封包會排隊等待,緩衝區會被填滿,最終導致封包遺失。一個較好的起點,是每個實體核心對應一個佇列。對於多核心伺服器,建議先依照「每個實體核心一個佇列」開始。你可以透過 ethtool -l 查看目前設定。這個指令會顯示預設最大值以及目前啟用的數量。
你還必須考慮超執行緒。邏輯核心會共用實體執行單元。依邏輯核心數分配佇列,往往會引入競爭。因此應優先從每個實體核心一個佇列開始,然後再測試。如果 CPU 使用率保持較低,且封包遺失消失,那麼你大致就找到了一個較好的平衡點。如果封包遺失仍然存在,有時並不是需要更多佇列,反而可能需要更少。減少佇列數量可以降低中斷向量消耗,在高負載系統中甚至能夠緩解中斷遺失。
結合工作負載與佇列分布來判斷
你的工作負載類型會影響理想的佇列分布方式。高吞吐型負載,例如大量傳輸、AI 訓練或儲存流量,通常更適合更多佇列以及更積極的中斷合併。合併會讓每次中斷處理更多資料封包,從而提升吞吐量。相反地,延遲敏感型負載,例如交易系統或即時互動流量,則需要相反的策略。關閉自適應合併,並盡量減少批次處理,可以降低中斷延遲。
下表展示了不同工作負載類型與合併策略及範例設定之間的對應關係。
| 工作負載類型 | 合併策略 | 範例 ethtool 設定 |
|---|---|---|
| 高吞吐型 | 啟用自適應合併,或設定較高的手動值 | ethtool -C ens1f0 adaptive-rx on adaptive-tx on |
| 延遲敏感型 | 關閉自適應合併,並盡量減少批次處理 | ethtool -C ens1f0 adaptive-rx off adaptive-tx off |
較大的佇列有助於繁忙系統維持高吞吐量,但也會帶來更高延遲。若佇列分布偏向吞吐量最佳化,互動類資料封包可能會排在大量流量資料之後等待處理。如果你更想最佳化延遲而不是吞吐量,可以關閉 TSO、GSO、UFO 和 GRO。除非系統正在處理極高的資料速率,否則你通常不會看到明顯的 CPU 影響或吞吐量下降。若你希望對排隊位元組數設定一個硬性上限,可以將新值寫入 limit_max 檔案。
調整佇列數量並驗證修復效果
使用 ethtool -L 修改佇列數量
你已經確定了目標值,現在可以開始套用。ethtool 工具能夠在無需重新開機的情況下修改作用中的佇列數量。使用 -L 參數並搭配 combined 選項,即可同時設定接收與傳送佇列。
使用
ethtool -L將網卡的傳送與接收組合佇列設定為 8$ sudo ethtool -L eth0 combined 8
例如,對於一台 16 核心伺服器,你可以執行 ethtool -L ens1f0 combined 16 來設定最大值。修改後一定要用 ethtool -l 再次確認。這個指令會顯示目前作用中的佇列數。如果結果與你的目標一致,表示修改已生效。如果驅動拒絕該請求,就需要檢查預設最大值。有些介面卡會將 combined 的數量限制在固定範圍內。
一次只修改這一個變數。此時先不要去調整環形緩衝區或中斷合併參數。單一變數變更能讓測試結果更加清楚。
監控並重新測試封包遺失情況
修改完成後,立即重新檢查封包遺失計數器。執行 ethtool -S,觀察 rx_dropped 或 tx_dropped 是否繼續上升。若計數器保持不變,則表示修復有效。你也可以透過 /proc/net/softnet_stat 查看核心層級的封包遺失情況。該檔案中的第 2 欄表示丟棄的資料封包數量,第 3 欄表示 time_squeeze,意味著 CPU 過於繁忙,無法及時處理流量。即時觀察這些計數器,有助於捕捉新的封包遺失問題。
接下來,用 iperf3 進行吞吐量測試。先啟動伺服端,再執行單一串流的用戶端測試,然後再用平行串流壓滿連線。將結果與最初的基準進行比較。如果吞吐量保持穩定且封包遺失消失,表示這次調整成功了。伺服器網卡佇列數量配置不當導致的封包遺失問題,通常會在這裡呈現出明顯改善。
延遲同樣重要。你可以先用 ping 做一個基礎檢查。如果想看更詳細的延遲分布,可以執行 sockperf ping-pong。這個測試能夠發現 ping 可能遺漏的延遲抖動問題。
最後,還要留意副作用。監控 /proc/interrupts,觀察中斷速率如何變化。這個檔案能幫助你驗證每個接收佇列是否映射到合適的 CPU。不過,僅靠這個指標並不能可靠反映實際資料量,因為很多驅動在與 NAPI 子系統協作時會關閉網卡中斷,而中斷合併也會影響這些數字。為了獲得更完整的視圖,也請同時檢查 /proc/softirqs。如果你發現 CPU 使用率升高,或者出現新的延遲尖峰,就表示需要重新評估佇列數量。有時減少佇列可以降低中斷向量消耗,緩解中斷壓力。如果在完成這些檢查後仍有封包遺失,就進入下一節做更深入的調校。
調校作業系統網路堆疊與網卡設定
如果在調整佇列數量後封包遺失依然存在,就需要進一步深入調校。通常還剩兩個問題:環形緩衝區過小,以及中斷處理不均衡。把這兩點修正後,往往就能解決問題。
增大環形緩衝區以減少封包遺失
環形緩衝區是在網路介面與核心之間起臨時儲存作用的區域。當突發流量超過緩衝容量時,網卡就會丟棄資料封包。增大緩衝區大小,可以降低這種風險。
先檢查目前的 nic ring buffer 設定。使用 ethtool -g 查看數值。該指令會顯示每個佇列對應的 rx 和 tx 環形緩衝區大小。若目前值較小,就表示還有擴充空間。
使用 -G 參數增大環形緩衝區。例如執行 sudo ethtool -G eth0 rx 4096 tx 4096。盡可能把接收與傳送緩衝區都設定到較大的值,最大可到 4096。再用 ethtool -g 確認新的 ring buffer 大小。更大的 ring buffer 能在突發流量下為系統爭取更多處理時間,從而在不改變佇列數的前提下減少封包遺失。不過,更大的緩衝區也會增加延遲。對於延遲敏感型負載,建議測試較為適中的數值。
設定 IRQ 親和性以實現負載平衡
即使佇列數量正確、nic ring buffer size 也設定得當,如果中斷分布不均衡,仍然可能造成封包遺失。每個接收佇列都會產生一個中斷請求。當多個 IRQ 集中落在同一個核心上時,該核心會過載,而其他核心卻處於閒置狀態。設定 irq affinity 的目的,就是把負載平均分散開來。
先檢查中斷分布。執行 cat /proc/interrupts | grep ethX,查看哪些核心正在處理網路中斷。再搭配 top 觀察 CPU 使用情況。若發現分布明顯不均,就表示問題存在。
你可以透過 irqbalance --debug 除錯 IRQ 分布。如果自動平衡未啟用,就需要手動為每個佇列設定 CPU 核心親和性。將核心遮罩寫入 /sys/class/net/ethX/queues/rx-0/rps_cpus。例如,要把佇列 0 指派給 CPU 核心 0,可以向該檔案寫入數值 1。你可以先透過 lscpu | grep '^CPU(s):' 列出可用核心,以確認正確的遮罩。
均衡的 irq affinity 能降低單核心壓力,防止封包遺失持續累積。搭配合適的 nic ring buffers 後,你的 nic settings 將能更有效率地處理流量。如果問題仍未解決,可以進一步減少佇列數量。更少的佇列可以降低中斷向量消耗,從而減輕 IRQ 封包遺失。你也可以在網路介面上設定 QoS,優先保障關鍵流量。
此外,還可以在作業系統層級調整 Linux 核心的接收與傳送緩衝區。使用 sysctl 修改 net.core.rmem_max 和 net.core.wmem_max。把它們設定得更高,可以更好地容納突發流量,從而承接那些已經通過網卡、但超過核心處理能力的資料封包。
現在你已經擁有一套四步處理流程。第一步,用封包遺失計數器診斷問題。第二步,根據硬體選擇最佳佇列數量。第三步,使用 ethtool 套用修改。第四步,在必要時繼續調校作業系統網路堆疊。每次只改動一個變數,驗證每一次結果,並記錄所有設定。伺服器網卡佇列數量配置不當導致封包遺失,是一個很常見的問題,但它完全可以被修復。不妨今天就花幾分鐘檢查一下你的伺服器佇列數量,這也許能幫你省下數小時的網路疑難排解時間。
常見問題
我如何確認是佇列數量導致了封包遺失?
執行 ethtool -S,觀察 rx_dropped 和 tx_dropped。如果這些計數器持續上升,並且佇列數量超過 CPU 核心數,那麼這種不匹配很可能就是根本原因。
我的伺服器最佳佇列數量是多少?
建議從每個實體核心一個佇列開始。使用 ethtool -l 查看目前數量,再根據工作負載進行調整。更多佇列有利於吞吐量,更少佇列則有助於降低中斷壓力。
修改佇列數量需要重新開機嗎?
不需要。你可以使用 ethtool -L 立即修改作用中的佇列數量,新值會即時生效。隨後使用 ethtool -l 進行確認即可。
調整佇列會影響應用程式效能嗎?
會。更多佇列通常能提升大量流量傳輸的吞吐表現;而對於延遲敏感型應用程式,更少的佇列並關閉合併功能,往往效果更好。建議根據你的實際工作負載進行測試。
如果調校佇列後仍然封包遺失,我該怎麼辦?
可以使用 ethtool -G 增大環形緩衝區大小;設定 IRQ 親和性,讓中斷在各核心之間平均分布;如果中斷向量消耗仍然過高,則繼續減少佇列數量。
