1

我有传输 UDP 流的 C 应用程序。它在大多数服务器上运行良好,但在少数服务器上很疯狂。

我在服务器上有100 Mbps的网络连接说eth1 。使用这个网络,我通常传输(TX)大约10-30 Mbps的UDP 流,这个网络连接将有大约100-300 Kbps的 RX 到服务器。我在服务器中有其他网络连接说eth0,C 应用程序从该服务器接收 UDP 流并转发到 100 Mbps 网络连接eth1

我的应用程序使用阻塞 sendto()功能在eth1中传输 UDP 数据包。数据包长度可变,从 17 字节到最大 1333 字节。但大多数时候,超过 1000 个字节。

问题是:有时eth1sendto上的功能块会持续大约 1 秒。这种情况每 30 秒到 3 分钟发生一次。当阻塞时,我将有很多 UDP 数据包缓冲在内核从eth0的 UDP 接收缓冲区中,C 应用程序从那里接收数据包。一旦从eth1上的长阻塞调用返回,C 应用程序将有大量缓冲数据包从eth0传输。然后 C 应用程序将所有这些缓冲的数据包与下一次调用一起传输。这将在从eth1接收 UDP 流的其他端点产生速率峰值。这将创建Zsendtosendtosendto像其他端点的速率图。所以这个像 Z 一样的飙升是我的问题。

我试图在内核设置中wmem_default从大约131 KB增加到5 MB以克服峰值。设置它可以解决我的峰值问题。现在我在其他端点上没有像 Z 这样的速率飙升,但我遇到了新问题。新问题是:我得到很多丢包而不是尖峰。我认为这可能是由于eth1的发送缓冲区累积了大量要发送的数据包,而从eth1发送当前数据包需要很多时间(这就是为什么可能会sendto长时间阻塞)。而在下一个瞬间,当 NIC 在短时间内从发送缓冲区发送所有累积的数据包时,这可能会导致网络拥塞,我可能会收到很多数据包丢失而不是峰值。

所以,这是第二个问题。但我认为根本原因是:为什么有时 NIC 在发送流量时会长时间暂停,每 30 秒到 3 分钟一次?

可能我需要查看eth1 驱动程序的 TX 环形缓冲区吗?当由于 NIC 未及时传输(由于随机长时间 TX 暂停)而导致套接字发送缓冲区变满时,接下来调用sendto套接字发送缓冲区中的空间块,这是否也会阻塞驱动程序 TX 环形缓冲区中的空间?

请不要告诉我 UDP 不可靠,我们无法控制丢包。我知道它的不可靠和 UDP 数据包可能会丢失。但我确信我们仍然可以做一些事情来减少数据包丢失。

编辑

我试图在内核设置中wmem_default从大约131 KB增加到5 MB以克服峰值。而且我还删除了阻塞sendto呼叫。现在我使用喜欢:sendto(sockfd, buf, len, MSG_DONTWAIT ,dest_addr, addrlen);使用大型发送缓冲区wmem_default。此外,由于发送缓冲区大,我没有收到任何错误EAGAINEWOULDBLOCK错误,但仍然有数据包丢失而不是尖峰。sendto

编辑

sendto由于具有巨大的非阻塞调用wmem_default,并且由于没有来自 的任何EAGAINEWOULDBLOCK错误sendto,尖峰已被删除,因为没有太多的数据包在eth0的接收缓冲区中累积。我认为它可能从应用程序方面解决。但主要问题是为什么网卡每隔几分钟就会变慢?可能的原因是什么?虽然它从长时间的 TX 暂停中恢复,并且可能会在发送缓冲区中累积大量数据包,这些数据包将在下一刻以突发的形式发送,并且拥塞网络因此大量数据包丢失。

更多更新

我使用相同的这个 C 应用程序在机器(127.0.0.1)中本地传输,并且我从未在本地遇到任何峰值或数据包丢失问题。

4

1 回答 1

1

问题是:有时在 eth1 上发送功能块大约 1 秒。

令人惊讶的是,阻塞sendto可能会阻塞。

问题是:有时在 eth1 上发送功能块大约 1 秒。

可能是IP 堆栈正在执行路径 MTU 发现

在 MTU 发现过程中,可能会丢弃来自数据报套接字的初始数据包。使用 UDP 的应用程序应该意识到这一点,而不是将其考虑到它们的数据包重传策略中。


我试图在内核设置中将 wmem_default 从大约 131 KB 增加到 5 MB 以克服峰值。

小心增加缓冲区大小。在某个限制之后,增加缓冲区大小只会增加排队数量,从而增加延迟,从而导致臭名昭著的bufferbloat


您也可以使用NIC Queuing Disciplines,它们负责丢弃传出的数据包。

于 2014-12-17T14:27:29.647 回答