我有传输UDP流的C应用程序。它适用于大多数服务器,但在少数服务器上很疯狂。
我在服务器上有 100 Mbps 网络连接说 eth1 。使用此网络,我通常在 10-30 Mbps UDP流周围传输(TX),此网络连接将具有 100-300 Kbps RX到服务器。我在服务器中有其他网络连接说 eth0 ,C应用程序从中接收UDP流并转发到100 Mbps网络连接, eth1 。
我的应用程序使用阻止 sendto()
函数在 eth1 中传输UDP数据包。数据包长度可变,从17个字节到最大1333个字节。但大多数时候,超过1000个字节。
问题是: eth1 上的某些时间sendto
功能块大约1秒钟。这种情况每30秒到3分钟发生一次。当sendto
阻塞时,我会在内核中从 eth0 缓冲UDP接收缓冲区中的大量UDP数据包,C应用程序从这里接收数据包。一旦sendto
从 eth1 上的长阻塞调用返回,C应用程序将有大量缓冲数据包从 eth0 传输。然后C应用程序通过下一次sendto
调用传输所有这些缓冲的数据包。这将在从 eth1 接收UDP流的其他端点处创建速率的峰值。这将在其他端点创建 Z ,如速率图。所以这个 Z喜欢率飙升是我的问题。
我尝试在内核设置中将wmem_default
从 131 KB 增加到 5 MB 以克服峰值。设置这个解决了我的尖峰问题。现在我没有在其他端点获得 Z像速率,但我遇到了新问题。新的问题是:我得到了大量的数据包丢失而不是尖峰。我认为这可能是由于发送缓冲区 eth1 累积大量数据包发送,而从 eth1 发送当前数据包需要花费大量时间(这就是为什么{{1}阻止长)。并且在下一瞬间,当NIC在短时间内从发送缓冲区发送所有累积的数据包时,这可能会导致网络拥塞,并且我可能会遇到大量数据包丢失而不是尖峰。
所以,这是第二个问题。但我认为根本原因是:为什么有时NIC会在每30秒到3分钟发送一次流量时暂停一次?
可能我需要查看eth1驱动程序的 TX环缓冲区?当套接字发送缓冲区由于NIC没有及时发送(由于随机的长TX暂停)而变满时,接下来调用sendto
阻塞套接字发送缓冲区中的空间,这也会阻止中的空间驱动程序TX环缓冲区?
请不要告诉我UDP不可靠,我们无法控制数据包丢失。我知道它的不可靠和UDP数据包可能会丢失。但我相信我们仍然可以做些什么来减少数据包丢失。
修改
我尝试在内核设置中将sendto
从 131 KB 增加到 5 MB 以克服峰值。 还我已删除阻止wmem_default
来电。现在我使用sendto
和sendto(sockfd, buf, len, MSG_DONTWAIT ,dest_addr, addrlen);
使用大型发送缓冲区。此外,由于发送缓冲区很大,我在wmem_default
上没有收到任何EAGAIN
或EWOULDBLOCK
错误,但仍然会丢失数据包而不是尖峰。
修改
作为非sendto
非阻塞sendto
来电,wmem_default
来自任何EAGAIN
或EWOULDBLOCK
来自sendto
,因为没有在 eth0 的接收缓冲区中累积的数据包很多。我认为它可以从应用方面解决。但主要问题是为什么NIC每隔一段时间就会减速?可能的原因是什么?虽然它从长时间的TX暂停中恢复,但可能会在发送缓冲区中累积大量数据包,这将在下一时刻作为突发发送并使网络拥塞大量丢包。
更新
我使用相同的C应用程序在机器(127.0.0.1)中进行本地传输,并且我从未在本地获得任何尖峰或数据包丢失问题。
答案 0 :(得分:1)
问题是:有时会在eth1上发送功能块大约1秒钟。
令人惊讶的是,阻止sendto
可能会阻止。
问题是:有时会在eth1上发送功能块大约1秒钟。
可能是IP stack is performing path MTU discovery:
当MTU发现正在进行时,可能会丢弃来自数据报套接字的初始数据包。使用UDP的应用程序应该意识到这一点,而不是将其考虑在内,因为它们的数据包重传策略。
我尝试在内核设置中将wmem_default从大约131 KB增加到5 MB以克服峰值。
小心增加缓冲区大小。在一定限制之后,增加缓冲区大小只会增加排队量并因此延迟,从而导致臭名昭着的bufferbloat。
你也可以玩NIC Queuing Disciplines,他们负责丢弃传出的数据包。