網路丟包怎麼排查(如何解決網路丟包問題)
背景:在使用Linux作為伺服器作業系統時,為了達到高併發處理能力,充分利用機器效能,經常會進行一些核心引數的調整優化,但不合理的調整常常也會引起意想不到的其他問題,怎麼識別並處理這些問題呢?
本文就一次Linux伺服器丟包故障的處理過程,結合Linux核心引數說明和TCP/IP協議棧相關的理論,帶大家一起來看看常見的丟包故障定位方法及解決思路。
1.問題現象
本次故障的反饋現象是:從辦公網訪問公網伺服器不穩定,伺服器某些埠訪問經常超時,但Ping測試顯示客戶端與伺服器的鏈路始終是穩定低延遲的。
通過在伺服器端抓包,我們發現還有兩個特點:
從辦公網訪問伺服器有多個客戶端,是同一個出口IP,有少部分是始終能夠穩定連線的,另一部分間歇訪問超時或延遲很高
同一時刻的訪問,無論哪個客戶端的資料包先到達,服務端會及時處理部分客戶端的SYN請求,對另一部分客戶端的SYN包“視而不見”
2. 如何排查,怎樣解決?
伺服器能正常接收到資料包,問題可以限定在兩種可能:
- 部分客戶端發出的資料包本身異常;
- 伺服器處理部分客戶端的數觸發了某種機制丟棄了資料包。
因為出問題的客戶端能夠正常訪問公網上其他服務,後者的可能性更大。那麼,有哪些情況會導致Linux伺服器丟棄資料包?
一、防火牆攔截
伺服器埠無法連線,通常就是檢視防火牆配置了,雖然這裡已經確認同一個出口IP的客戶端有的能夠正常訪問,但也不排除配置了DROP特定埠範圍的可能性。
如何確認?
檢視iptables Filter表,確認是否有相應規則會導致此丟包行為,容易排除防火牆攔截的可能性。
二、連線跟蹤表溢位
除了防火牆本身配置DROP規則外,與防火牆有關的還有連線跟蹤表nf_conntrack,Linux為每個經過核心網路棧的資料包,生成一個新的連線記錄項,當伺服器處理的連線過多時,連線跟蹤表被打滿,伺服器會丟棄新建連線的資料包。
如何確認?
通過dmesg可以確認是否有該情況發生:如果輸出值中有“nf_conntrack: table full,dropping packet”,說明伺服器nf_conntrack表已經被打滿。
通過conntrack工具或/proc檔案系統檢視nf_conntrack表實時狀態:在本案例中,當前連線數遠沒有達到跟蹤表最大值,因此排除這個因素。
如何解決?
如果確認伺服器因連線跟蹤表溢位而開始丟包,首先需要檢視具體連線判斷是否正遭受DOS攻擊,如果是正常的業務流量造成,則可以考慮調整nf_conntrack的引數:
- nf_conntrack_max決定連線跟蹤表的大小,預設值是65535,可以根據系統記憶體大小計算一個合理值:CONNTRACK_MAX = RAMSIZE(in bytes)/16384/(ARCH/32),如32G記憶體可以設定1048576
- nf_conntrack_buckets決定儲存conntrack條目的雜湊表大小,預設值是nf_conntrack_max的1/4,延續這種計算方式:BUCKETS = CONNTRACK_MAX/4,如32G記憶體可以設定262144
- nf_conntrack_tcp_timeout_established決定ESTABLISHED狀態連線的超時時間,預設值是5天,可以縮短到1小時,即3600。
三、Ring Buffer溢位
排除了防火牆的因素,我們從底向上來看Linux接收資料包的處理過程,首先是網絡卡驅動層。
如下圖所示,物理介質上的資料幀到達後首先由NIC(網路介面卡)讀取,寫入裝置內部緩衝區Ring Buffer中,再由中斷處理程式觸發Softirq從中消費,Ring Buffer的大小因網絡卡裝置而異。
當網路資料包到達(生產)的速率快於核心處理(消費)的速率時,Ring Buffer很快會被填滿,新來的資料包將被丟棄。
如何確認?
通過ethtool -S指令或檢視/proc/net/dev可以得到因Ring Buffer滿而丟棄的包統計,在統計項中以fifo標識:本案例中伺服器的接收方向的fifo丟包數並沒有增加,自然也排除這個原因。
如何解決?
如果發現伺服器上某個網絡卡的fifo數持續增大,可以去確認CPU中斷是否分配均勻,也可以嘗試增加Ring Buffer的大小,通過ethtool -g可以檢視網絡卡裝置Ring Buffer最大值,ethtool -G修改Ring Buffer當前設定。
四、netdev_max_backlog溢位
netdev_max_backlog是核心從NIC收到包後,交由協議棧(如IP、TCP)處理之前的緩衝佇列。每個CPU核都有一個backlog佇列,與Ring Buffer同理,當接收包的速率大於核心協議棧處理的速率時,CPU的backlog佇列不斷增長,當達到設定的netdev_max_backlog值時,資料包將被丟棄。
如何確認?
通過檢視/proc/net/softnet_stat可以確定是否發生了netdev backlog佇列溢位。其中:
- 每一行代表每個CPU核的狀態統計,從CPU0依次往下
- 每一列代表一個CPU核的各項統計:第一列代表中斷處理程式收到的包總數;第二列即代表由於netdev_max_backlog佇列溢位而被丟棄的包總數
在本案例的伺服器統計中,並沒有因為netdev_max_backlog導致的丟包。
如何解決?
netdev_max_backlog的預設值是1000,在高速鏈路上,可能會出現上述第二列統計不為0的情況,可以適當調大核心引數
net.core.netdev_max_backlog到2000來解決。
感謝大家的收藏與轉發,記得要點選關注喲,您的關注,是我們更新的動力!