调整接收缓冲区大小
跑实时语音会议的时候,偶尔会听到“咔咔”的断续声,很多人以为是网络差,其实可能是系统默认的UDP接收缓冲区太小。Linux下可以通过修改 /proc/sys/net/core/rmem_max 和 rmem_default 来提升上限。比如:
echo 16777216 > /proc/sys/net/core/rmem_max
echo 4194304 > /proc/sys/net/core/rmem_default这样能把最大接收缓冲区提到16MB,适合高吞吐场景,比如视频直播推流或者多人在线游戏服务器。
启用SO_REUSEPORT提升多进程负载
一台服务器上跑多个UDP服务实例,如果都监听同一个端口,传统做法容易冲突。使用 SO_REUSEPORT 可以让多个进程安全地绑定同一地址和端口,内核自动做负载分发。代码片段如下:
int sock = socket(AF_INET, SOCK_DGRAM, 0);
int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse));这在部署高性能DNS缓存或NTP服务时特别实用,避免单点处理瓶颈。
关闭不必要的校验和验证
某些嵌入式设备或虚拟机环境中,网卡不支持UDP校验和卸载,系统就得用CPU算,占用资源。如果内部网络环境稳定,可以考虑在确保数据链路可靠的条件下,关闭校验和验证。例如在Linux中通过 ethtool 关闭:
ethtool -K eth0 rx-udp_tunnel-csum-receive off注意:公网或复杂网络别轻易关,不然丢包率可能悄悄飙升。
合理设置TTL减少广播风暴
做局域网发现功能时,常用UDP广播。但如果TTL(Time to Live)设得太大,包可能会被转发到不该去的子网,浪费带宽还可能引发交换机泛洪。一般局域通信把TTL设为1或2就够了:
int ttl = 2;
setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));就像在楼道里喊人,不用让声音传到隔壁小区。
避免频繁创建套接字
有些程序每次发数据都新建UDP socket,用完就关。这种写法看似简单,实则容易耗尽端口,还增加延迟。正确做法是复用同一个socket,尤其是发送频率高的场景,比如监控数据上报。连接池式的管理能明显降低系统调用开销。
监控丢包情况定位瓶颈
优化前先看问题在哪。用 netstat -su 查看UDP丢包统计,重点关注 receive buffer errors 这一项。如果数字一直在涨,说明接收缓冲区不够,该调大了。配合 ss -u 观察当前UDP连接状态,能快速判断是否堆积严重。