問題現象
某局點出現一個奇怪的現象,客戶端給服務端發送消息,服務端僅能收到小部分消息,大部分消息從客戶端發出后,服務端都未收到。
問題定位
-
初步分析
- 根據現象初步分析,有可能是網絡原因導致消息到服務端不可達,但是又無法佐證,因為確實有部分消息是能夠被服務端接收到的。
- 服務端應用問題,通過某些渠道了解到,接收端是客戶自己實現的一個程序,可能是程序存在bug,導致消息丟失。該原因定位較困難,客戶表示可以接收其他發送端消息,拒絕從接收端應用開始排查。
-
抓包
- 根據初步分析的第一點猜測,我們決定進行抓包進行分析,由于發送端使用的是udp包,所以我們使用tcpdump工具,在發送端進行抓包,抓包后的結果是,所有的數據包均被tcpdump捕獲。
- 根據第一步的結果可以得出結論,問題并非出在發送應用端,接著我們在接收端進行tcpdump抓包,結果發現,發送端發出來的包,在服務端并沒有全部被抓取到。問題已經顯而易見了。
-
分析
根據上述抓包結果,基本可以定界到中間的網絡傳輸將數據包丟棄。而后排查網絡問題,發現是網絡中的防火墻將數據包大于1472字節的包攔截并丟棄了。而防火墻的這一行為為出廠時默認配置,目的是為了防止網絡攻擊。
問題根因
對于udp數據包,當數據包過大時,網卡會將其自動分片發送,而在這個案例中,udp報文里ip層的flag為0x02,即df(don’t fragment)位為1,表示不允許分片發送。
df = 1的情況有以下兩種
-
操作系統配置
/proc/sys/net/ipv4/ip_no_pmtu_disc
參數值
若上述參數值為0(默認),則表示可分片。
若上述參數值為2,則強制不進行分片。
更詳細的用法可以百度查一下。
這個案例中發送端機器參數為。 -
確認發送端網卡的mtu值是否大于1500
這里為什么是1500呢?因為當udp數據包發出去后,會在報文中添加28字節的報文頭,其中8字節的udp層,20字節的ip層,而1500 - 28 = 1472,所以防火墻會將大于1472字節的數據進行攔截。
經過排查后發現發送端的機器的mtu值為8192,所以當從發送端將大于1472,小于8166的數據包發送出去時,報文中所攜帶的df值為1,后續經過的所有路由都沒有進行分片,導致數據包到達防火墻后被過濾。
查詢網卡mtu方法:ifconfig
正常情況下,該值都為1500,所以數據包能被正常分片在1472字節內。
解決方案
修改網卡mtu值,這個操作可以直接百度到了。
ifconfig 網卡名稱 mtu 1500 up
或
vim /etc/sysconfig/network-scripts/對應網卡的ifcfg文件
新增一行MTU="1500"
保存后退出,并執行service network restart
重啟網卡服務。