我有一个第三方组件,它试图在某种情况下向太多单独的地址发送过多的UDP消息。这是在软件启动并且情况是暂时的时发生的突发。我实际上不确定这些消息的数量是多少还是每个消息都转到一个单独的IP地址。
无论如何,更改底层协议或有问题的组件不是一个选项,所以我正在寻找一种解决方法。 StackTrace看起来像这样:
java.io.IOException: No buffer space available
at java.net.PlainDatagramSocketImpl.send(Native Method)
at java.net.DatagramSocket.send(DatagramSocket.java:612)
此问题(至少)发生在Java版本1.6.0_13和1.6.0_10以及Linux版本Ubuntu 9.04和RHEL 4.6上。
是否有任何Java系统属性或Linux配置调整可能会有所帮助?
答案 0 :(得分:9)
我终于确定了问题所在。 Java IOException具有误导性,因为它是“没有可用的缓冲区空间”,但根本问题是本地ARP表已被填充。在Linux上,默认的ARP表查找是1024(文件/ proc / sys / net / ipv4 / neigh / default / gc_thresh1,/ proc / sys / net / ipv4 / neigh / default / gc_thresh2,/ proc / sys / net / ipv4 /嘶/默认/ gc_thresh3)。
在我的情况下(我假设您的情况)发生的事情是,您的Java代码是从与目标地址位于同一子网中的IP地址发送UDP数据包。在这种情况下,Linux计算机将执行ARP查找以将IP地址转换为硬件MAC地址。由于您要将数据包发送到许多不同的IP,因此本地ARP表会快速填满,达到1024,这就是抛出Java异常的时候。
解决方案很简单,要么通过编辑前面提到的文件来增加限制,要么将服务器移动到与目标地址不同的子网中,这会导致Linux机箱不再执行邻居ARP查找(而是由网络上的路由器处理。)
答案 1 :(得分:3)
当发送大量消息时,特别是在Linux中的千兆以太网上,内核的库存参数通常不是最佳的。您可以通过以下方式增加用于联网的Linux内核缓冲区大小:
echo 1048576 > /proc/sys/net/core/wmem_max
echo 1048576 > /proc/sys/net/core/wmem_default
echo 1048576 > /proc/sys/net/core/rmem_max
echo 1048576 > /proc/sys/net/core/rmem_default
扎根。
或使用sysctl
sysctl -w net.core.rmem_max=8388608
有大量的网络选项
答案 2 :(得分:1)
可能有点复杂,但据我所知,Java使用SPI 1 模式作为网络子库。这允许您更改用于各种网络操作的实现。如果您使用OpenJDK,那么您可以获得一些提示如何以及如何包含您的实现。然后,在您的实现中,您可以通过一些休眠来减慢I / O.
或者,只是为了好玩,您可以使用修改后的实现覆盖默认的DatagramSocket。拥有相同的包名称 - 据我所知 - 它将优先于默认的JRE类。至少这种方法适用于一些有缺陷的第三方库。
修改强>
1 服务提供者接口是一种在API中分离客户端和服务代码的方法。此分离允许不同的客户端和不同的提供者实现通常可以从以Impl
结尾的名称中识别,就像在堆栈中一样,跟踪java.net.PlainDatagramSocketImpl
是提供者实现,其中DatagramSocket是客户端API。
您评论说您不希望整个过程减慢通信速度。有几种方法可以避免它,例如测量代码中的时间并在第一次传入方法调用开始的前1-2分钟内减慢通信速度。然后你可以跳过睡眠。
另一种选择是识别库中行为不端的类,JAD并修复它。然后替换库中的原始类文件。
答案 3 :(得分:0)
我目前也在使用Debian和amp; RHEL。此时我相信我已将其隔离到NIC和/或NIC驱动程序。你有什么硬件配置这也会出现这个问题?这似乎只发生在我们最近收购的具有Broadcom Corporation NetXtreme II BCM5708千兆以太网NIC的新型Dell PowerEdge服务器上。
我也可以确认它是在短窗口中快速生成到许多不同IP地址的出站UDP数据包。我试图编写一个可以重现它的简单Java应用程序(因为我们的应用程序正在使用snmp4j)。
修改强>
在这里查看我的答案:Java IOException: No buffer space available while sending UDP packets on Linux
答案 4 :(得分:0)
当我尝试使用WIFI连接到数据库在两个本地JVM中运行coherence群集时,我遇到此错误。 如果我使用以太网运行它 - 它运行良好。