網絡丟包排查思路

網絡丟包排查思路
1.防火牆確認:看防火牆是否配置了DROP特定端口範圍的可能性
方法:查看iptables filter表,確認是否有相應規則會導致此丟包行爲,命令: sudo iptables-save -t filter
2.連接跟蹤表溢出
除了防火牆本身配置DROP規則外,與防火牆有關的還有連接跟蹤表nf_conntrack,Linux爲每個經過內核網絡棧的數據包,生成一個新的連接記錄項,當服務器處理的連接過多時,連接跟蹤表被打滿,服務器會丟棄新建連接的數據包。
1)問題確認:通過dmesg可以確認是否有該情況發生:
    命令:dmesg |grep nf_conntrack,如果輸出值中有“nf_conntrack: table full, dropping packet”,說明服務器nf_conntrack表已經被打滿。
通過/proc文件系統查看nf_conntrack表實時狀態:
# 查看nf_conntrack表最大連接數
$ cat /proc/sys/net/netfilter/nf_conntrack_max
65536
# 查看nf_conntrack表當前連接數
$ cat /proc/sys/net/netfilter/nf_conntrack_count
7611
2)解決辦法:如果確認服務器因連接跟蹤表溢出而開始丟包,首先需要查看具體連接判斷是否正遭受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。
命令行配置:
$ sysctl -w net.netfilter.nf_conntrack_max=1048576
$ sysctl -w net.netfilter.nf_conntrack_buckets=262144
$ sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600
3.Ring Buffer溢出
排除了防火牆的因素,我們從底向上來看Linux接收數據包的處理過程,首先是網卡驅動層。
物理介質上的數據幀到達後首先由NIC(網絡適配器)讀取,寫入設備內部緩衝區Ring Buffer中,再由中斷處理程序觸發Softirq從中消費,Ring Buffer的大小因網卡設備而異。當網絡數據包到達(生產)的速率快於內核處理(消費)的速率時,Ring Buffer很快會被填滿,新來的數據包將被丟棄。
       1)判斷方法:通過ethtool或/proc/net/dev可以查看因Ring Buffer滿而丟棄的包統計,在統計項中以fifo標識:
$ ethtool -S eth0|grep rx_fifo
    rx_fifo_errors: 0
$ cat /proc/net/dev
    Inter-|   Receive                                                |  Transmit
可以看到服務器的接收方向的fifo丟包數並沒有增加,說明此階段不存在丟包。
     2)如果是,解決辦法:
如果發現服務器上某個網卡的fifo數持續增大,可以去確認CPU中斷是否分配均勻,也可以嘗試增加Ring Buffer的大小,通過ethtool可以查看網卡設備Ring Buffer最大值,修改Ring Buffer當前設置:
查看eth0網卡Ring Buffer最大值和當前設置
$ ethtool -g eth0
Ring parameters for eth0:
 
Pre-set maximums:
RX:     4096  
RX Mini:    0
RX Jumbo:   0
TX:     4096  
Current hardware settings:
RX:     1024  
RX Mini:    0
RX Jumbo:   0
TX:     1024  
# 修改網卡eth0接收與發送硬件緩存區大小
$ ethtool -G eth0 rx 4096 tx 4096
Pre-set maximums:
RX:     4096  
RX Mini:    0
RX Jumbo:   0
TX:     4096  
Current hardware settings:
RX:     4096  
RX Mini:    0
RX Jumbo:   0
TX:     4096
4.netdev_max_backlog溢出
netdev_max_backlog是內核從NIC收到包後,交由協議棧(如IP、TCP)處理之前的緩衝隊列。每個CPU核都有一個backlog隊列,與Ring Buffer同理,當接收包的速率大於內核協議棧處理的速率時,CPU的backlog隊列不斷增長,當達到設定的netdev_max_backlog值時,數據包將被丟棄。
      
1)判斷方法: 通過查看/proc/net/softnet_stat可以確定是否發生了netdev backlog隊列溢出:
其中:
    每一行代表每個CPU核的狀態統計,從CPU0依次往下;
每一列代表一個CPU核的各項統計:第一列代表中斷處理程序收到的包總數;第二列即代表由於netdev_max_backlog隊列溢出而被丟棄的包總數。
從上面的輸出可以看出,這臺服務器統計中,並沒有因爲netdev_max_backlog導致的丟包。
2)解決辦法
netdev_max_backlog的默認值是1000,在高速鏈路上,可能會出現上述第二列統計不爲0的情況,可以通過修改內核參數net.core.netdev_max_backlog來解決:
    sysctl -w net.core.netdev_max_backlog=2000
5.反向路由過濾
反向路由過濾機制是Linux通過反向路由查詢,檢查收到的數據包源IP是否可路由(Loose mode)、是否最佳路由(Strict mode),如果沒有通過驗證,則丟棄數據包,設計的目的是防範IP地址欺騙攻擊。rp_filter提供了三種模式供配置:
0 - 不驗證
1 - RFC3704定義的嚴格模式:對每個收到的數據包,查詢反向路由,如果數據包入口和反向路由出口不一致,則不通過
2 - RFC3704定義的鬆散模式:對每個收到的數據包,查詢反向路由,如果任何接口都不可達,則不通過
1)如何確認
查看當前rp_filter策略配置:
$ cat /proc/sys/net/ipv4/conf/eth0/rp_filter
0
如果這裏設置爲1,就需要查看主機的網絡環境和路由策略是否可能會導致客戶端的入包無法通過反向路由驗證了。
從原理來看這個機制工作在網絡層,因此,如果客戶端能夠Ping通服務器,就能夠排除這個因素了。
2)如何解決
根據實際網絡環境將rp_filter設置爲0或2:
$ sysctl -w net.ipv4.conf.all.rp_filter=2
 或
 $ sysctl -w net.ipv4.conf.eth0.rp_filter=2
6.半連接隊列溢出
半連接隊列指的是TCP傳輸中服務器收到SYN包但還未完成三次握手的連接隊列,隊列大小由內核參數tcp_max_syn_backlog定義。
當服務器保持的半連接數量達到tcp_max_syn_backlog後,內核將會丟棄新來的SYN包。
1)如何確認
通過dmesg可以確認是否有該情況發生:
$ dmesg | grep "TCP: drop open request from"
半連接隊列的連接數量可以通過netstat統計SYN_RECV狀態的連接得知
2)如何解決
tcp_max_syn_backlog的默認值是256,通常推薦內存大於128MB的服務器可以將該值調高至1024,內存小於32MB的服務器調低到128,同樣,該參數通過sysctl修改:netstat -ant|grep SYN_RECV|wc -l
sysctl -w net.ipv4.tcp_max_syn_backlog=1024
另外,上述行爲受到內核參數tcp_syncookies的影響,若啓用syncookie機制,當半連接隊列溢出時,並不會直接丟棄SYN包,而是回覆帶有syncookie的SYC+ACK包,設計的目的是防範SYN Flood造成正常請求服務不可用。


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章