程序是Java編寫,基於Netty框架寫的客戶端及服務端。html
客戶端大數據量持續發UDP數據,做爲UDP服務器出現了部分數據頻繁丟失觸發程序自身重傳邏輯。
經過GC日誌對比發現丟包的時間點偶有處於Full GC,說明Java程序接收間歇性stop world的不是根因。java
經過watch -n 1 -d 'cat /proc/net/udp >> /usr/udpDump.txt'
在發送數據的過程當中持續觀察Udp緩衝區的情況linux
經過watch -n 1 -d 'netstat -su >> /usr/udpStats.txt'
持續觀察Udp的stats輸出git
定論:
默認的UDP socket讀緩衝區不夠引起系統丟棄UDP包。
服務端代碼優化設置UDP socket讀緩衝區爲2M,代碼以下github
Bootstrap selfBootStrap = new Bootstrap(); selfBootStrap.group(group); selfBootStrap.channel(NioDatagramChannel.class); selfBootStrap.option(ChannelOption.SO_BROADCAST, true); // 這一行設置了UDP socket讀緩衝區爲2M selfBootStrap.option(ChannelOption.SO_RCVBUF, 1024 * 2048); selfBootStrap.handler(channelInitializer); selfBootStrap.localAddress(selfPort);
理論上Udp socket讀緩衝區設置爲2M在咱們的測試場景下已經足夠。優化後雖有改善但仍有丟包現象。bash
定論:
應用層設置了UDP socket緩衝區不必定在Linux上生效,緣由在於Linux對Udp socket緩衝區存有系統級限制,超過該限制的緩衝區大小無效。服務器
Windows對socket的緩衝區沒有限制框架
要點分析:
Linux經過net.core.rmem_max
控制Udp的讀緩衝區,經過net.core.wmem_max
控制Udp的寫緩衝區。
在程序的啓動sh腳本里添加以下代碼修改net.core.rmem_max
socket
# 服務器默認UDP讀緩衝區最大128K。修改成2G。解決UDP丟包問題 rmemCount=`cat /etc/sysctl.conf|grep "net.core.rmem_max" | wc -l` if [ ${rmemCount} -eq 0 ] then echo "net.core.rmem_max = 2147483647" >> /etc/sysctl.conf sysctl -p fi
腳本的做用就是修改/etc/sysctl.conf
文件,並鍵入sysctl -p
命令使自定義參數生效。
資料參見Improving UDP Performance by Configuring OS UDP Buffer Limits、UDP Drops on Linuxide