我有传输 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 流的其他端点产生速率峰值。这将创建Zsendto
sendto
sendto
像其他端点的速率图。所以这个像 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
。此外,由于发送缓冲区大,我没有收到任何错误EAGAIN
或EWOULDBLOCK
错误,但仍然有数据包丢失而不是尖峰。sendto
编辑
sendto
由于具有巨大的非阻塞调用wmem_default
,并且由于没有来自 的任何EAGAIN
或EWOULDBLOCK
错误sendto
,尖峰已被删除,因为没有太多的数据包在eth0的接收缓冲区中累积。我认为它可能从应用程序方面解决。但主要问题是为什么网卡每隔几分钟就会变慢?可能的原因是什么?虽然它从长时间的 TX 暂停中恢复,并且可能会在发送缓冲区中累积大量数据包,这些数据包将在下一刻以突发的形式发送,并且拥塞网络因此大量数据包丢失。
更多更新
我使用相同的这个 C 应用程序在机器(127.0.0.1)中本地传输,并且我从未在本地遇到任何峰值或数据包丢失问题。