UDP丢包原因排查:双服务器多网卡C++应用问题咨询
UDP跨服务器转发丢包排查与实践疑问解答
问题背景与环境
- 两台服务器X、Y,各配备双网卡:X的x1、x2;Y的y1、y2。其中x2与y2处于同一局域网,x1、y1分别用于接收UDP组播数据包。
- 两台服务器部署了相同的C++应用,以X为例的核心逻辑:
- 线程1(绑定独立CPU核心):以非阻塞模式打开socket绑定x1,循环调用
recvfrom()接收组播包,通过同一socket调用sendto()转发至Y的y2网卡IP,最后将数据存入并发队列。 - 线程2(绑定独立CPU核心):以非阻塞模式打开socket绑定x2,接收Y转发的数据包后存入同一并发队列。
- 线程3(绑定独立CPU核心):消费并发队列中的数据,执行业务逻辑。
- 线程1(绑定独立CPU核心):以非阻塞模式打开socket绑定x1,循环调用
核心疑问
- 在同一线程的同一socket上同时执行收发操作是否为不良实践?如果是,更优方案是什么?
- 若tcpdump捕获的数据包数量与应用接收的数量一致,是否可以排除因两次
recvfrom()调用间隔过长导致的丢包? - 若发送端服务器tcpdump捕获了100个出站数据包,而接收端仅捕获95个入站数据包,该如何定位丢失的5个数据包?它们可能丢失在哪些网络层?
已完成排查与数据
- x2和y2的tcpdump结果显示:Y的y2接收的数据包数量少于X的x2发送的数量,反向转发也存在类似情况;其中X到Y的数据包频率更高(约10个/秒)、尺寸更大(256字节),丢包率也更高。
- 两台服务器的默认接收缓冲区(通过
cat /proc/sys/net/core/rmem_default查看)均为212992。 netstat -suna显示以下UDP相关指标无增长:- packets to unknown port received
- packet receive errors
- receive buffer errors
- send buffer errors
- 使用sockperf在x2与y2之间测试,在更高消息频率和吞吐量设置下无丢包。
问题解答
1. 同一线程同一socket同时收发是否为不良实践?
这是不推荐的实践,核心问题有两点:
- 收发操作相互干扰:即使是非阻塞socket,
sendto()也可能因发送缓冲区满返回EAGAIN或进入短暂等待,会挤占recvfrom()的执行时间,导致组播包接收不及时,增大丢包概率。 - 逻辑耦合度高:同一socket绑定x1网卡做组播接收,同时用它向y2转发,会让socket的网络属性(如绑定网卡、组播订阅)与转发逻辑绑定,后续维护和排查问题的成本会很高。
更优方案:
- 拆分收发socket:线程1单独创建两个非阻塞socket,一个绑定x1专门负责组播接收,另一个专门用于向y2转发数据(可绑定x2网卡,避免跨网卡转发的额外开销)。
- 转发逻辑异步化:如果转发压力较大,可将转发任务放入单独的并发队列,由专门的转发线程处理,避免占用接收线程的CPU时间。
2. tcpdump捕获数与应用接收数一致,能否排除recvfrom()间隔过长的丢包?
可以基本排除这种情况,原因如下:
- tcpdump是在网卡驱动层捕获数据包,只要tcpdump能抓到,说明数据包已经到达服务器并进入内核缓冲区。
- 若
recvfrom()间隔过长,会导致内核接收缓冲区被占满,此时内核会丢弃新数据包,这种情况下tcpdump依然能抓到包,但应用接收不到,两者数量会出现差异。 - 既然两者数量一致,说明内核缓冲区没有因应用处理不及时而溢出,
recvfrom()的间隔处于合理范围。
3. 发送端抓包100个、接收端仅95个,如何定位丢包?
这种丢包发生在发送端网卡之后、接收端网卡之前的网络路径中,可能涉及的层级和排查步骤如下:
可能的丢包层级
- 数据链路层:局域网交换机端口拥塞、MAC地址学习异常、链路故障(如网线松动、网卡协商速率不匹配)。
- 网络层:VLAN配置异常、ARP缓存失效(虽然是同一局域网,但可能存在ARP表项过期或错误)。
- 传输层基本可排除:因为应用能收到部分包,且
netstat无未知端口相关指标增长,说明接收端UDP端口正常监听。
定位步骤
- 在中间网络设备抓包:如果局域网有管理型交换机,在X的x2连接的交换机端口和Y的y2连接的端口同时抓包,确认数据包是否成功离开X所在端口、是否到达Y所在端口。
- 检查服务器网卡状态:
- 查看网卡硬件卸载功能:执行
ethtool -k x2、ethtool -k y2,TSO/GRO等卸载功能可能导致数据包在网卡层丢失,可临时关闭后测试。 - 查看网卡错误统计:执行
ethtool -S x2、ethtool -S y2,检查rx_errors、tx_errors、dropped等指标是否增长。
- 查看网卡硬件卸载功能:执行
- 调整包参数测试:你已经发现大尺寸、高频率的包丢包率更高,可进一步降低包大小或频率,验证丢包是否缓解,判断是否是链路带宽或缓冲区不足导致。
- 调大网络栈缓冲区:虽然默认接收缓冲区为212992,可临时调大接收缓冲区上限:
sysctl -w net/core/rmem_max=4194304,同时在应用中通过setsockopt()设置SO_RCVBUF参数,验证是否能降低丢包。
内容的提问来源于stack exchange,提问作者AlgRev
相关产品推荐
相关产品推荐

