Java IOException:在 Linux 上发送 UDP 数据包时没有可用的缓冲区空间

发布于 2024-07-25 15:38:56 字数 507 浏览 1 评论 0原文

我有一个第三方组件,它试图在某种情况下向太多单独的地址发送太多的 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 配置调整?

I have a third party component which tries to send too many UDP messages to too many separate addresses in a certain situation. This is a burst which happens when the software is started and the situation is temporary. I'm actually not sure is it the plain amount of the messages or the fact that each of them go to a separate IP address.

Anyway, changing the underlying protocol or the problematic component is not an option, so I'm looking for a workaround. The StackTrace looks like this:

java.io.IOException: No buffer space available
    at java.net.PlainDatagramSocketImpl.send(Native Method)
    at java.net.DatagramSocket.send(DatagramSocket.java:612)

This issue occurs (at least) with Java versions 1.6.0_13 and 1.6.0_10 and Linux versions Ubuntu 9.04 and RHEL 4.6.

Are there any Java system properties or Linux configuration tweaks which might help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

红衣飘飘貌似仙 2024-08-01 15:38:57

可能有点复杂,但据我所知,Java 使用 SPI1 模式作为网络子库。 这允许您更改用于各种网络操作的实现。 如果您使用 OpenJDK,那么您可以获得一些关于如何以及在您的实现中包装什么的提示。 然后,在您的实现中,您可以通过一些睡眠来减慢 I/O 速度。

或者,只是为了好玩,您可以使用修改后的实现覆盖默认的 DatagramSocket。 具有相同的包名称,并且据我所知,它将优先于默认的 JRE 类。 至少这个方法对我在一些有缺陷的第三方库上有效。

编辑:

1服务提供商接口是一种在 API 中分离客户端和服务代码的方法。 这种分离允许不同的客户端和不同的提供者实现。 通常可以从以 Impl 结尾的名称来识别,就像在堆栈跟踪中 java.net.PlainDatagramSocketImpl 是提供程序实现,其中 DatagramSocket 是客户端 API。

您评论说您不想全程减慢沟通速度。 有几种技巧可以避免这种情况,例如测量代码中的时间并在第一次传入方法调用开始的前 1-2 分钟内减慢通信速度。 然后你就可以跳过睡眠了。

另一种选择是识别库中行为不当的类,对其进行 JAD 并修复。 然后替换库中原来的类文件。

Might be a bit complicated but as I know, Java uses the SPI1 pattern for the network sub-library. This allows you to change the implementation used for various network operations. If you use OpenJDK then you could gain some hints how and what to wrap with your implementation. Then, in your implementation you slow down the I/O with some sleeps for example.

Or, just for fun, you could override the default DatagramSocket with your modified implementation. Have the same package name for it and - as I know - it will take precedence over the default JRE class. At least this method worked for me on some buggy 3rd party library.

Edit:

1Service Provider Interface is a method to separate client and service code within an API. This separation allows different client and different provider implementations. Can be recognized from the name ending in Impl usually, just like in your stack trace java.net.PlainDatagramSocketImpl is the provider implementation where the DatagramSocket is the client side API.

You commented that you don't want to slow down the communication the entire way. There are several hacks to avoid it, for example measure the time in your code and slow the communication within the first 1-2 minutes starting at your first incoming method call. Then you can skip the sleep.

Another option would be to identify the misbehaving class in the library, JAD it and fix it. Then replace the original class file in the library.

却一份温柔 2024-08-01 15:38:57

我目前在 Debian 和 Debian 上也看到了这个问题。 RHEL。 此时,我相信我已将其隔离到 NIC 和/或 NIC 驱动程序。 您的什么硬件配置也出现此问题? 这种情况似乎只发生在我们最近购买的配备 Broadcom Corporation NetXtreme II BCM5708 千兆位以太网 NIC 的新型 Dell PowerEdge 服务器上。

我也可以确认,它是在一个短窗口内快速生成到许多不同 IP 地址的出站 UDP 数据包。 我尝试编写一个简单的 Java 应用程序来重现它(因为我们的应用程序是使用 snmp4j 进行的)。

编辑

在这里查看我的答案:Java IOException: 在 Linux 上发送 UDP 数据包时没有可用的缓冲区空间

I'm also currently seeing this problem as well with both Debian & RHEL. At this point I believe I've isolated it down to the NIC and/or the NIC driver. What hardware configuration do you have this also exhibits this problem? This seems to only occur on new Dell PowerEdge servers that we recently acquired that have Broadcom Corporation NetXtreme II BCM5708 Gigabit Ethernet NICs.

I too can confirm that it is the rapid generation of outbound UDP packets to many different IP addresses in a short window. I've attempted to write a simple Java application that can reproduce it (since ours is occurring with snmp4j).

EDIT

Look at my answer here: Java IOException: No buffer space available while sending UDP packets on Linux

梦里梦着梦中梦 2024-08-01 15:38:57

当我尝试使用 WIFI 连接到数据库在两个本地 JVM 中运行一致性集群时,出现此错误。
如果我使用以太网运行它 - 它运行良好。

I have got this error when i tried to run coherence cluster in two local JVM using the WIFI connection to database..
If i run it using the ethernet - it runs well.

小…红帽 2024-08-01 15:38:56

我终于确定了问题所在。 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 /neigh/default/gc_thresh3)。

在我的情况下(我假设你的情况也是如此),你的 Java 代码正在从与你的目标地址位于同一子网中的 IP 地址发送 UDP 数据包。 在这种情况下,Linux 机器将执行 ARP 查找,将 IP 地址转换为硬件 MAC 地址。 由于您将数据包发送到许多不同的 IP,因此本地 ARP 表很快就会填满,达到 1024,此时就会抛出 Java 异常。

解决方案很简单,要么通过编辑我之前提到的文件来增加限制,要么将您的服务器移动到与目标地址不同的子网中,这会导致 Linux 机器不再执行邻居 ARP 查找(而是由一个网络上的路由器)。

I've finally determined what the issue is. The Java IOException is misleading since it is "No buffer space available" but the root issue is that the local ARP table has been filled. On Linux, the default ARP table lookup is 1024 (files /proc/sys/net/ipv4/neigh/default/gc_thresh1, /proc/sys/net/ipv4/neigh/default/gc_thresh2, /proc/sys/net/ipv4/neigh/default/gc_thresh3).

What was happening in my case (and I assume your case), is that your Java code is sending out UDP packets from an IP address that is in the same subnet as your destination addresses. When this is the case, the Linux machine will perform an ARP lookup to translate the IP address into the hardware MAC address. Since you are blasting out packets to many different IPs the local ARP table fills up quickly, hits 1024, and that is when the Java exception is thrown.

The solution is simple, either increase the limit by editing the files I mentioned earlier, or move your server into a different subnet than your destination addresses, which then causes the Linux box to no longer perform neighbor ARP lookups (instead will be handled by a router on the network).

黑寡妇 2024-08-01 15:38:56

当发送大量消息时,尤其是在 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

以 root 身份。

或者使用 sysctl

sysctl -w net.core.rmem_max=8388608 

有大量的网络选项

请参阅 IBM 的 Linux 网络调优
更多调整信息

When sending lots of messages, especially over gigabit ethernet in Linux, the stock parameters for your kernel are usually not optimal. You can increase the Linux kernel buffer size for networking through:

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

As root.

Or use sysctl

sysctl -w net.core.rmem_max=8388608 

There are tons of network options

See Linux Network Tuning by IBM
and More tuning information

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文