Linux 5.4内核UDP接收缓冲区报错但rx_queue为空问题求助
问题排查与解决方案
第一步:核对UDP缓冲区全量配置
你仅调整了net.core.rmem_max参数,还需完成以下配置校验和调整:
- 检查
net.core.rmem_default参数:该参数决定了新建UDP socket的默认接收缓冲区大小,如果业务程序没有主动调用setsockopt(SO_RCVBUF)自定义缓冲区,实际生效的缓冲区大小由该参数决定。建议同步将其调整为和rmem_max一致:
查看当前值命令:sysctl net.core.rmem_default
调整命令:sysctl -w net.core.rmem_default=目标值,调整后需同步写入/etc/sysctl.conf避免重启后配置失效 - 确认业务程序是否硬编码了接收缓冲区大小:如果应用层主动通过
SO_RCVBUF参数设置了socket缓冲区,系统级的rmem_max调整不会生效,需要修改应用配置,或者去掉硬编码逻辑使用系统默认值
补充说明:你贴的
/proc/net/udp日志中rx_queue值为0x900(十进制2304),说明内核态socket队列中确实存在未被用户态读取的报文,netstat显示Recv-Q为0是因为二者统计口径不同,此时也需要同步排查应用层的UDP报文处理效率是否足够,避免因为应用处理速度跟不上导致队列溢出丢包。
第二步:检查UDP全局内存阈值
Linux内核有UDP全局内存限制,由net.ipv4.udp_mem三个参数控制(单位为内存页,默认页大小为4KB),分别对应最小值、压力阈值、最大值。当全局UDP占用内存超过压力阈值时,即使单个socket缓冲区没满,内核也会丢弃新到的UDP报文,此时会直接统计到receive buffer errors中。
- 查看当前配置命令:
sysctl net.ipv4.udp_mem - 你当前系统可用内存充足,可以直接将三个值上调为原来的2-3倍,例如原值为
16384 32768 65536,可调整为32768 65536 131072。
第三步:内核层丢包排查
如果上述配置调整无效,按以下步骤排查:
- 查看全量协议栈错误计数器:执行
nstat -az Udp* Ip*,重点关注UdpInCsumErrors(校验和错误计数)、IpReasmFails(分片重组失败计数)、IpInDiscards(IP层丢包计数)。如果UdpInCsumErrors持续增长,说明报文在校验阶段就被丢弃,和缓冲区无关,需要排查网卡硬件、链路,或者关闭网卡校验和卸载验证,临时关闭命令为ethtool -K eth0 rx off tx off && ethtool -K eth1 rx off tx off。 - 排查netfilter规则丢包:执行
iptables -t filter -L INPUT -v -n查看INPUT链的规则命中计数,确认是否有规则匹配到你的UDP端口并执行了DROP操作,若对应计数增长和UDP丢包增长一致即可确认。 - 排查中断均衡:执行
cat /proc/interrupts | grep eth查看两块物理网卡的中断是否均匀分布在不同CPU核心,执行mpstat -P ALL 1 3查看各核心的软中断(%soft)占用是否均匀。如果所有网卡中断都集中在单个核心,即使单核心整体负载0.2,也可能出现短时间内UDP报文处理不及时丢包,可通过配置RPS或者irqbalance服务均衡中断。
第四步:内核Bug适配
你使用的5.4版本内核存在已知的UDP接收侧优化Bug,如果上述排查都无异常,可以尝试上调net.ipv4.udp_rmem_min参数,增加UDP socket最小预留接收缓冲区大小,避免内核在内存回收时误回收UDP缓冲区空间。
内容的提问来源于stack exchange,提问作者sibsonx
相关产品推荐
相关产品推荐

