Java IOException: нет свободного места в буфере при отправке пакетов UDP в Linux - PullRequest
5 голосов
/ 25 июня 2009

У меня есть сторонний компонент, который пытается отправить слишком много 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, которые могут помочь?

Ответы [ 5 ]

9 голосов
/ 10 октября 2009

Я наконец определил, в чем проблема. Java IOException вводит в заблуждение, поскольку оно «Нет доступного пространства буфера», но основная проблема заключается в том, что локальная таблица ARP заполнена. В Linux поиск таблицы ARP по умолчанию - 1024 (файлы / proc / sys / net / ipv4 / adj / default / gc_thresh1, / proc / sys / net / ipv4 / lie / default / gc_thresh2, / proc / sys / net / ipv4 /neigh/default/gc_thresh3).

В моем случае (и я предполагаю, что в вашем случае) происходило то, что ваш Java-код отправляет UDP-пакеты с IP-адреса, который находится в той же подсети, что и ваши адреса назначения. В этом случае машина Linux выполнит поиск ARP, чтобы преобразовать IP-адрес в аппаратный MAC-адрес. Поскольку вы отправляете пакеты на множество разных IP-адресов, локальная таблица ARP быстро заполняется, достигает 1024, и тогда возникает исключение Java.

Решение простое: либо увеличьте лимит, отредактировав файлы, которые я упоминал ранее, либо переместите свой сервер в другую подсеть, чем адреса назначения, что приведет к тому, что Linux-бокс больше не будет выполнять поиск соседних ARP (вместо этого будет обрабатывается маршрутизатором в сети).

3 голосов
/ 25 июня 2009

При отправке большого количества сообщений, особенно через гигабитный Ethernet в 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 

Есть множество вариантов сети

См. Сетевая настройка Linux от IBM и Дополнительная информация о настройке

1 голос
/ 25 июня 2009

Может быть немного сложнее, но, как я знаю, Java использует шаблон SPI 1 для сетевой подбиблиотеки. Это позволяет изменить реализацию, используемую для различных сетевых операций. Если вы используете OpenJDK, вы можете получить некоторые подсказки, как и что обернуть с вашей реализацией. Затем в вашей реализации вы замедляете ввод-вывод, например, с помощью нескольких снов.

Или, просто для удовольствия, вы можете переопределить стандартный DatagramSocket с помощью вашей измененной реализации. Иметь для него такое же имя пакета, и - как я знаю - он будет иметь приоритет над классом JRE по умолчанию. По крайней мере, этот метод работал для меня в какой-то глючной сторонней библиотеке.

Edit:

1 Интерфейс поставщика услуг - это метод разделения кода клиента и службы в API. Такое разделение допускает разные реализации клиента и разных поставщиков. Может распознаваться по имени, оканчивающемуся на Impl, обычно, как в трассировке стека java.net.PlainDatagramSocketImpl - это реализация провайдера, где DatagramSocket - это API на стороне клиента.

Вы прокомментировали, что не хотите полностью замедлять общение. Существует несколько способов избежать этого, например, измерить время в вашем коде и замедлить обмен данными в течение первых 1-2 минут, начиная с вашего первого входящего вызова метода. Тогда вы можете пропустить сон.

Другим вариантом было бы определить неверно работающий класс в библиотеке, JAD и исправить его. Затем замените исходный файл класса в библиотеке.

0 голосов
/ 03 сентября 2012

Я получил эту ошибку, когда попытался запустить кластер когерентности в двух локальных JVM, используя соединение WIFI с базой данных. Если я запускаю его, используя Ethernet - он работает хорошо.

0 голосов
/ 07 октября 2009

В настоящее время я также вижу эту проблему как с Debian, так и с RHEL. На данный момент я считаю, что я изолировал его для NIC и / или драйвера NIC. Какая аппаратная конфигурация у вас есть, это также показывает эту проблему? Похоже, это происходит только на новых серверах Dell PowerEdge, которые мы недавно приобрели и которые оснащены сетевыми сетевыми картами Ethernet NetXtreme II BCM5708 от Broadcom.

Я тоже могу подтвердить, что это быстрая генерация исходящих пакетов UDP на множество разных IP-адресов в коротком окне. Я попытался написать простое Java-приложение, которое может воспроизводить его (поскольку наше происходит с snmp4j).

EDIT

Посмотрите на мой ответ здесь: Java IOException: Нет свободного места в буфере при отправке пакетов UDP в Linux

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...