一次内存引起的网络丢包问题排查

💡 原文中文,约4100字,阅读约需10分钟。
📝

内容提要

某服务器上线即丢包,网卡计数器显示rx_prio0_buf_discard。排除DCB、PCIe等因素后,通过server diff对比正常机器,发现内存有ECC错误记录。测试内存带宽,node 1仅约700MB/s,为node 0的1/17,确认内存故障导致收包链路处理能力不足而丢包。关闭绑定node 1的网卡后丢包消失。

🔎

延伸解读

从丢包计数器定位问题方向

文章指出,网卡计数器中的 rx_prio0_buf_discard 是排查关键。该计数增加表明接收方向因缓冲区不足而丢弃数据包,通常指向主机侧收包处理能力不足,而非链路或光模块故障。这提示排查时不应只关注 CRC 和光模块,而应深入检查网卡计数器,区分丢包发生在入口还是出口,从而缩小范围。

内存故障如何间接导致网络丢包

文章分析,NIC 通过 DMA 将数据写入内存,路径涉及 PCIe、IOMMU、CPU 互联和内存控制器。当内存子系统异常时,RX 路径的处理和缓冲区回收能力下降,导致 NIC 入口缓冲区无法及时清空,最终表现为 rx_prio0_buf_discard。因此,网络丢包有时需要从内存健康状态入手排查。

NUMA 节点内存带宽差异的警示

通过 stream 测试,文章发现 node 1 的内存带宽仅约 700MB/s,约为 node 0 的 1/17,且本地和跨节点访问均异常。这直接证明 node 1 内存存在严重性能问题。对于多 NUMA 架构服务器,应定期检查各节点内存带宽,避免因单节点降级影响绑定该节点的网卡或应用性能。

验证与缓解:关闭异常节点网卡

文章通过关闭绑定到 node 1 的网卡端口,使丢包消失,验证了问题根源。虽然单卡模式下网卡使用率翻倍,但丢包为零,说明异常内存节点是丢包主因。这提供了一种临时缓解思路:在无法立即更换内存时,可调整中断绑定或下线异常节点相关网卡,以恢复网络稳定性。

Q&A

服务器一上线就丢包,网卡计数器显示 rx_prio0_buf_discard,可能是什么原因?

根据文章,该丢包最终确认是内存故障导致。内存子系统异常会降低主机收包链路的处理和 buffer 回收能力,使 NIC ingress buffer 无法及时 drain,从而表现为 rx_prio0_buf_discard。

rx_prio0_buf_discard 丢包应该先排查哪些方向?

文章先检查了网卡 CRC、光模块,均正常;然后怀疑 DCB buffer 不足,但调大或调小 buffer 丢包依旧,排除 DCB;接着检查 PCIe 带宽和状态、调整 Interrupt coalescing,也都没有效果。最终通过 server diff 对比正常机器,发现内存 ECC 错误和内存带宽异常。

如何用 server diff 定位服务器异常?

server diff 是作者在没有思路时使用的手段:拿一台正常机器和一台异常机器,对比 sysctl 参数、kernel 参数、硬件规格等,找出差异点。文章通过这种方式发现了 IPMI SEL 中的 Uncorrectable ECC DIMMB5 记录、mcelog 的 corrected error,以及后续内存带宽测试异常。

内存故障为什么会导致网络收包丢包?

Linux 收包链路上,NIC DMA 到内存的路径是:PCIe NIC → PCIe Root Port/Root Complex → IOMMU → CPU Mesh/Interconnect → LLC(L3) / Memory Controller → DRAM。内存子系统异常会显著降低 host RX path 的处理和 buffer 回收能力,可能造成 NIC ingress buffer 无法及时 drain,最终表现为 rx_prio0_buf_discard。

怎么测试服务器内存带宽是否正常?

文章使用 stream.c 配合 numactl 分别测试不同 NUMA node 的内存带宽。例如:numactl -C 2 -m 0 ./stream 和 numactl -C 2 -m 1 ./stream。测试发现 node 1 的内存速度只有约 700MB/s,仅为 node 0 的 1/17,从而确认 node 1 内存有问题。

如何验证丢包确实是由 node 1 内存故障引起的?

由于网卡是双网口 bond,port 1 中断绑定到 node 0 的 CPU,port 2 中断绑定到 node 1 的 CPU。关闭 port 2 后,node 1 不再被使用,机器上线后丢包消失,从而验证了只有 node 1 的内存有问题。

🏷️

标签

➡️

继续阅读