介绍
本文档的目的是帮助找出丢失组播数据包的原因并进行一些调整以尽量减少此类丢失。
组播数据包丢失的原因有多种。
UDP 协议本身牺牲了性能的可靠性,并且不保证数据报的传递。 因此,数据包在网络传输过程中可能会丢失。
即使数据包到达网络节点,也并不总是意味着应用程序接收到它,因为在处理接收到的数据包时会经过几个级别,在每个级别上都可能会丢失。
网络数据包的典型路径如图 1 所示。
图1
首先,网络适配器(NIC)接收并处理网络数据包。 NIC 有自己的硬件环形缓冲区。当网络数据流高于 NIC 可以处理时,最新的数据将覆盖最旧的数据。这种可能性取决于 NIC 的特性,例如计算性能和硬件缓冲区大小。
接下来,经过网卡处理后,进入操作系统缓冲区,也可能溢出。来自所有 NIC 的所有应用程序和辅助数据包的所有数据包都通过此缓冲区。
因此,在操作系统层面丢失的可能性取决于:
- 操作系统缓冲区的大小
- 系统性能
- 系统负载
- 网络相关的系统负载
即使应用程序不使用 NIC,它也取决于 NIC 的数量:它会通过 ARP 或 ICMPv6 等辅助协议产生一些额外的负载。
然后,它进入应用程序从中获取数据包的套接字(socket)缓冲区。如果应用程序无法按时从socket中取出数据包,缓冲区将溢出,数据包将丢失。
因此,在应用层面丢失的可能性取决于:
- socket 缓冲区大小
- 应用程序获取数据的速度
诊断
网络适配器缓冲区溢出诊断
Linux
在 Linux 上,可以使用 netstat -i –udp <NIC>
命令检测网络适配器缓冲区溢出,其中 RX-DRP 列显示适配器丢弃的数据包数。
例如:
netstat -i –udp eth0
Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 0 109208 0 3 0 82809 0 0 0 BMRU
此输出标识适配器丢弃了三个数据包。
为了缓解网络适配器缓冲区溢出,应增加网络适配器缓冲区的大小。
Windows
在 Windows 上,可以使用 netstat -e
命令检测网络适配器缓冲区溢出。
例如:
netstat -eInterface StatisticsReceived Sent
Bytes 2126595129 3580282555
Unicast packets 100602496 384905740
Non-unicast packets 3975342 1522900
Discards 2 0
Errors 3 0
Unknown protocols 0
Discards 显示 NIC 拒绝的数据包数量(可能是因为它们已损坏)。
Errors 显示在发送或接收过程中发生的错误数(可能是因为 NIC 出现问题)。
操作系统内核网络缓冲区溢出诊断
Linux
在 Linux 上 watch -d "cat /proc/net/snmp | grep -w Udp"
命令,InErrors 列显示操作系统 UDP 队列溢出时丢弃的 UDP 数据包数。
操作系统缓冲区溢出可以通过以下方式缓解:
- 增加操作系统内核网络缓冲区的大小。
- 通过使用用户空间网络堆栈/内核绕过(kernel-bypass)中间件(例如 Solarflare 的 OpenOnload)从数据包路径中排除操作系统内核网络缓冲区。
- 关闭所有未使用的与网络相关的应用程序和服务,以最大限度地减少系统负载。
- 在您的系统上只留下合理数量的工作网卡。
例如:
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
Udp: 1273 25 9 6722 0 0
此输出标识操作系统丢弃了九个数据包。
您还可以使用 watch -d "cat /proc/net/pid/snmp | grep -w Udp"
命令在每个进程的基础上看到这一点。
Windows
要检查 Windows 上的 UDP 统计信息,请使用命令:netstat -s -p udp
IPv4 的 UDP 统计信息
Datagrams Received = 85463
No Ports = 123
Receive Errors = 0
Datagrams Sent = 75022
Receive Errors
指示与操作系统相关的接收错误的数量。
应用程序级套接字缓冲区溢出诊断
Linux
在 Linux 上 watch -d "cat /proc/net/snmp | grep -w Udp"
命令,RcvbufErrors 列显示应用程序套接字缓冲区溢出时丢弃的 UDP 数据包数。
例如:
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
Udp: 8273 25 0 8720 15 0
此输出标识应用程序丢弃了 15 个数据包。
您还可以使用 watch -d "cat /proc/net/pid/snmp | grep -w Udp"
命令在每个进程的基础上看到这一点。
应用程序级套接字缓冲区溢出可以通过以下方式缓解:
- 应用程序更快地为其接收套接字缓冲区提供服务(例如,通过使用专用线程来接收 UDP 数据包和/或增加其优先级)。
- 应用程序增加其接收套接字缓冲区的大小。 有时系统管理员还必须增加全局套接字缓冲区限制,否则应用程序级别的增加将不起作用。
- 将应用程序(或其接收线程)分配给专用 CPU 内核。
- 提高应用程序的优先级(例如使用
nice
和ionice
Linux 命令)。 - 关闭所有未使用的与网络相关的应用程序和服务,以最大限度地减少系统负载。
调整
网络适配器缓冲区调整
Linux
要查看适配器的缓冲区设置,请运行 ethtool -g <NIC>
命令。
例如:
ethtool –g eth1:Ring parameters for eth1:
Pre-set maximums:
RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 4096
Current hardware settings:
RX: 4096
RX Mini: 0
RX Jumbo: 0
TX: 1024
输出中有两个部分。 第一部分是预设最大值(Pre-set maximums),表示可以为每个可用参数设置的最大值。 第二部分显示每个参数的当前值。
要设置 RX 环形缓冲区(ring buffer)大小,请运行 ethtool -G <NIC> rx NEW-BUFFER-SIZE
命令。
更改将立即生效,无需重新启动系统甚至网络堆栈。
这些更改是针对网卡本身而不是针对操作系统进行的。 这不会更改内核网络堆栈参数,但会更改固件中的 NIC 参数。
较大的环形缓冲区大小可以吸收较大的数据包突发而不会丢失,但可能会因为工作集大小增加而降低效率。
现代网卡的典型环形缓冲区大小值约为 4096,如果您的网卡较少,请考虑硬件升级。
操作系统内核网络缓冲区调整
Linux
运行 sysctl -A | grep net | grep 'mem\|backlog' | grep 'udp_mem\|rmem_max\|max_backlog'
命令检查系统级缓冲区的当前设置。
例如:
net.core.rmem_max = 131071
net.core.netdev_max_backlog = 1000
net.ipv4.udp_mem = 1501632 2002176 3003264
将最大套接字接收缓冲区大小增加到 64 MB:
sysctl -w net.core.rmem_max=67108864
增加可分配的最大总缓冲区空间。这是以页面为单位(4096 字节)测量的:
sysctl -w net.ipv4.udp_mem="262144 327680 393216"
请注意,net.ipv4.udp_mem
在页面中工作,因此要计算以字节为单位的大小,请将值乘以 PAGE_SIZE,其中 PAGE_SIZE = 4096 (4K)。那么最大 udp_mem
大小(以字节为单位)为 385152 * 4096 = 1,577,582,592。
增加传入数据包的队列大小:
sysctl -w net.core.netdev_max_backlog=2000
通过运行 sysctl -A | grep net | grep 'mem\|backlog' | grep 'udp_mem\|rmem_max\|max_backlog'
命令。
要使这些更改永久编辑或创建 /etc/sysctl.conf
文件并在那里添加更改。
应用程序级套接字缓冲区调整
Linux, Windows
为了减少数据包丢失,应用程序必须能够在最新的数据覆盖之前从套接字缓冲区获取数据。因此,应该增加套接字级别的缓冲区。在 OnixS 市场数据处理程序中,这可以通过使用 HandlerSettings::udpSocketBufferSize
配置设置来完成。推荐值为 8388608 (8 MiB)。
附加工具
如果你在应用程序中遇到多播数据包丢失,则可能值得运行一些独立工具来了解有关该问题的更多信息。
tcpdump
tcpdump 是一个强大的命令行数据包分析器,它允许绕过操作系统网络堆栈直接从 NIC 捕获所有多播数据。
例如:
tcpdump -n multicast -i <NIC>
Tcpdump 还支持多组不同的过滤策略。这允许捕获单个或多个多播组的网络数据包,并将其与应用程序接收的数据进行比较。如果应用程序显示一些数据包间隙,但 tcpdump 接收到所有数据,这意味着数据在网络堆栈或应用程序的某个地方丢失。否则,很可能是网络相关或网卡相关的原因。
组播测试
此工具可从 OnixS 支持团队 (support@onixs.biz) 获得。与 tcpdump 不同,它从应用程序级套接字读取数据。使用此工具允许以与应用程序相同的方式接收数据,这有助于检测应用程序内部的损失。
附录 A.“Solarflare 的应用程序加速/OpenOnload”
图 2
使用 Solarflare 的应用程序加速/OpenOnload 中间件允许数据包绕过系统内核。 这会带来一些性能优势,因为应用程序不执行与网络相关的内核调用。 如图 2 所示。
原文