程序是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