【问题标题】:How to minimize UDP packet loss如何最小化 UDP 数据包丢失
【发布时间】:2012-01-06 05:24:50
【问题描述】:

我每秒接收约 3000 个 UDP 数据包,每个数据包的大小约为 200 字节。我编写了一个 java 应用程序,它监听这些 UDP 数据包并将数据写入文件。然后服务器以先前指定的速率发送 15000 条消息。写入文件后,它仅包含约 3500 条消息。使用wireshark,我确认我的网络接口收到了所有15000条消息。之后我尝试更改套接字的缓冲区大小(最初是 8496 字节):

(java.net.MulticastSocket)socket.setReceiveBufferSize(32*1024);

该更改将保存的消息数量增加到约 8000 条。我不断将缓冲区大小增加到 1MB。之后,保存的消息数量达到了 ~14400。将缓冲区大小增加到更大的值不会增加保存的消息数量。我想我已经达到了允许的最大缓冲区大小。不过,我需要捕获我的网络接口接收到的所有 15000 条消息。

任何帮助将不胜感激。提前致谢。

【问题讨论】:

  • 我不会使用 UDP 来获取文件,因为文件有可能被损坏,为什么要使用 bot TCP?
  • 也许文件写入是瓶颈。您是否尝试使用具有更大缓冲区大小的 BufferedOutputStream(OutputStream out, int size)?
  • Brogrammer TCP 不是多播网络的选项。

标签: java udp multicast multicastsocket


【解决方案1】:

这是仅适用于 Windows 的答案,但网络控制器卡属性的以下更改对我们的用例造成了戏剧性的丢包率差异。

我们正在消耗大约 200 Mbps 的 UDP 数据,并且在中等服务器负载下遇到大量数据包丢失。

使用的网卡是华硕 ROG Aerion 10G 卡,但我希望大多数高端网络控制器卡具有类似的属性。您可以通过设备管理器->网卡->右键单击->属性->高级选项访问它们。

1.增加接收缓冲区的数量:

默认值为 512;我们可以将它增加到 1024。在我们的例子中,接受了更高的设置,但是一旦超过 1024,网卡就会被禁用。在网卡级别拥有更多的可用缓冲区使系统对传输延迟的容忍度更高数据从网卡缓冲区到我们的应用程序最终可以读取数据的套接字缓冲区。

2。将中断调节率设置为“关闭”:

如果我理解正确,中断审核会将多个“缓冲区填充”通知(通过中断)合并为一个通知。因此,CPU 将不那么频繁地被中断,并在每次中断期间获取多个缓冲区。这会减少 CPU 使用率,但会增加准备缓冲区在被获取之前被覆盖的机会,以防中断服务延迟。

此外,正如 Len Holgate 在评论中所建议的那样,我们增加了套接字缓冲区的大小(正如 OP 所做的那样)并且还在套接字级别启用了 循环缓冲 ,这也应该增加处理套接字缓冲区的延迟容忍度。

【讨论】:

    【解决方案2】:

    接收缓冲区大小在操作系统级别配置。

    例如在 Linux 系统上,sysctl -w net.core.rmem_max=26214400 如本文所述 https://access.redhat.com/site/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/jgroups-perf-udpbuffer.html

    【讨论】:

      【解决方案3】:

      我看到您正在使用 UDP 发送文件内容。在 UDP 中,数据包的顺序是不确定的。如果您不担心顺序,则将所有数据包放入队列中,并让另一个线程处理队列并将内容写入文件。这样,套接字读取器线程就不会因为文件操作而被阻塞。

      【讨论】:

        【解决方案4】:

        您似乎遇到的问题是延迟写入文件。在写入文件(或在另一个线程中写入文件)之前,我会将所有数据读入内存

        但是,如果没有能力要求再次发送数据包(TCP 为您做的事情),就无法确保 100% 的数据包通过 UDP 接收。

        【讨论】:

        • 这听起来像是正确的解决方案。基本上,如果您想要比套接字库允许的更大的缓冲区,则必须在您自己的应用程序中创建缓冲区,介于从网络读取线程和写入磁盘线程之间。
        【解决方案5】:

        闻起来像一个错误,很可能在您的代码中。如果 UDP 数据包通过网络传递,它们将在本地排队等待传递,正如您在 Wireshark 中看到的那样。也许您的程序在从其套接字读取时没有及时取得进展 - 是否有专门的线程来执行此任务?

        您可以通过检测哪些数据包被您的程序丢失来取得一些进展。如果所有丢失的数据包都是早期的,那么数据可能在程序等待接收它们之前就已经发送了。如果他们都晚了,也许它退出得太早了。如果它们定期进行,则您的代码中可能会出现一些问题,即循环接收数据包。等等

        在任何情况下,您似乎都非常担心丢失数据包。按照设计,UDP 不是一种可靠的传输方式。如果这些多播数据包的丢失对您的系统来说是一个问题(而不仅仅是出于性能原因您想解决的一个谜),那么系统设计就是错误的。

        【讨论】:

        • 是的,这个任务有专门的线程。我已经丢失了所有后面的消息。作为您的解释,我应该能够捕获已接收到我的网络接口的所有消息?我说的对吗?
        • 嗯,这一切都取决于你的平台,我希望。当然,在 Windows 上,如果它的缓冲区已满,网络堆栈将丢弃 UDP 数据报(这是允许的)——所以你会确切地看到你正在经历什么(wireshark 显示它们都到达了 NIC,而你的程序没有得到所有这些都是因为堆栈发现 recv 缓冲区已满并丢弃一些)。您可以使用 SIO_ENABLE_CIRCULAR_QUEUEING ioctl 调整删除它们的方式,请参阅msdn.microsoft.com/en-us/library/windows/desktop/… - 总之,更快地读取数据报。
        猜你喜欢
        • 1970-01-01
        • 2015-06-30
        • 2023-03-30
        • 2018-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-26
        相关资源
        最近更新 更多