2009-06-25 11 views
5

Tengo un componente de terceros que intenta enviar demasiados mensajes UDP a demasiadas direcciones separadas en una situación determinada. Esto es una explosión que ocurre cuando el software se inicia y la situación es temporal. De hecho, no estoy seguro de si es la cantidad total de los mensajes o el hecho de que cada uno de ellos vaya a una dirección IP diferente.Java IOException: no hay espacio en el búfer disponible al enviar paquetes UDP en Linux

De todos modos, cambiar el protocolo subyacente o el componente problemático no es una opción, entonces estoy buscando una solución alternativa. El StackTrace se ve así:

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

Este problema se produce (al menos) con las versiones de Java 1.6.0_13 y 1.6.0_10 y versiones de Linux Ubuntu 9.04 y RHEL 4.6.

¿Hay alguna propiedad del sistema Java o ajustes de configuración de Linux que puedan ser útiles?

Respuesta

3

Al enviar muchos mensajes, especialmente a través de gigabit ethernet en Linux, los parámetros de stock para su kernel generalmente no son óptimos. Puede aumentar el tamaño del búfer del kernel de Linux para redes a través de:

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 

Como root.

O uso sysctl

sysctl -w net.core.rmem_max=8388608 

hay un montón de opciones de red

Ver Linux Network Tuning by IBM y More tuning information

+0

Gracias. Además de esos parámetros, traté también de ajustar net.ipv4.udp_mem y net.ipv4.udp_wmem_min. Primero doblé, los valores, luego los doblé de nuevo, y finalmente los cambié para que fueran 10 veces más grandes que los valores predeterminados. Nada ha ayudado hasta ahora sin embargo. – auramo

+0

@auramo, ¿Qué JVM estás usando? ¿La compilación del sol o las cosas de OpenJDK/JVM de tu distribución? Yo recomendaría usar uno para su distribución, el abierto, de ser posible, ya que será menos "seguro" y tendrá una interfaz más precisa con el kernel/libc. –

+0

Estoy usando las versiones Sun de 1.6.0_13 y 1.6.0_10. Podría probar fácilmente con las versiones de OpenJDK, pero cambiar de la implementación de Sun a OpenJDK para el producto final sería una gran molestia en este punto del proyecto. – auramo

1

podría ser un poco complicado, pero que yo sepa, Java utiliza el SPI patrón para la sub biblioteca de la red. Esto le permite cambiar la implementación utilizada para varias operaciones de red. Si usa OpenJDK, entonces puede obtener algunas pistas sobre cómo y qué ajustar con su implementación. Luego, en su implementación, ralentiza la E/S con algunas horas de sueño, por ejemplo.

O, solo por diversión, puede anular el DatagramSocket predeterminado con su implementación modificada. Tiene el mismo nombre de paquete y, como sé, tendrá prioridad sobre la clase JRE predeterminada. Al menos este método funcionó para mí en alguna biblioteca de terceros con errores.

Editar:

interfaz de proveedor de servicio es un método para separar código de cliente y servicio dentro de una API. Esta separación permite diferentes implementaciones de clientes y proveedores diferentes. Puede reconocerse por el nombre que termina en Impl generalmente, al igual que en su seguimiento de pila java.net.PlainDatagramSocketImpl es la implementación del proveedor donde DatagramSocket es la API del lado del cliente.

Comentó que no desea ralentizar la comunicación durante todo el camino. Hay varios ataques para evitarlo, por ejemplo, mida el tiempo en su código y reduzca la velocidad de la comunicación dentro de los primeros 1 a 2 minutos a partir de su primera llamada al método entrante. Entonces puedes saltearte el sueño.

Otra opción sería identificar la clase que funciona mal en la biblioteca, JAD y repararlo. Luego reemplace el archivo de clase original en la biblioteca.

+0

¿Puede decirme qué es un patrón SPI? Quiero superar una ráfaga de tiempo de arranque de 1-2 minutos. Para eso, definitivamente no quiero ralentizar mi E/S UDP, que necesita ser rápida durante todo el tiempo que la aplicación se está ejecutando (es una aplicación de servidor). – auramo

+0

Ok, ese viejo patrón :-) – auramo

0

También estoy viendo este problema también con Debian & RHEL. En este punto, creo que lo he aislado en NIC y/o en el controlador NIC. ¿Qué configuración de hardware tiene esto también presenta este problema? Esto parece ocurrir solo en los nuevos servidores Dell PowerEdge que adquirimos recientemente y que tienen tarjetas de red (NIC) Gigabit Ethernet Broadcom Corporation NetXtreme II BCM5708.

También puedo confirmar que es la generación rápida de paquetes UDP de salida a muchas direcciones IP diferentes en una ventana corta. Intenté escribir una aplicación Java simple que pueda reproducirla (ya que la nuestra está ocurriendo con snmp4j).

EDITAR

Mira mi respuesta aquí: Java IOException: No buffer space available while sending UDP packets on Linux

+0

Mi problema ocurrió en muchas configuraciones de hw, en una estación de trabajo HP, así como en un servidor de bastidor. Eventualmente terminamos pirateando el componente subyacente (componente Java de otro equipo dentro de nuestra compañía) que causó un exceso de mensajes de red que desencadenó el problema. Ahora ese componente hace mucho menos solicitudes/respuestas UDP y el problema está resuelto para nosotros. – auramo

7

he determinado finalmente cuál es el problema. La IOException de Java es engañosa ya que es "No hay espacio de búfer disponible", pero el problema principal es que la tabla ARP local se ha llenado. En Linux, la búsqueda de tablas ARP por defecto es 1024 (archivos/proc/sys/net/ipv4/vecino/predeterminado/gc_thresh1,/proc/sys/net/ipv4/vecino/predeterminado/gc_thresh2,/proc/sys/net/ipv4/vecino/predeterminado/gc_thresh3).

Lo que estaba pasando en mi caso (y supongo que en su caso), es que su código Java está enviando paquetes UDP desde una dirección IP que está en la misma subred que sus direcciones de destino. Cuando este es el caso, la máquina Linux realizará una búsqueda ARP para traducir la dirección IP a la dirección MAC del hardware. Dado que está lanzando paquetes a muchas IP diferentes, la tabla ARP local se llena rápidamente, llega a 1024, y es entonces cuando se lanza la excepción Java.

La solución es simple, ya sea aumentar el límite editando los archivos que mencioné anteriormente o mover el servidor a una subred diferente a la de destino, lo que hace que el cuadro de Linux ya no realice búsquedas ARP contiguas (en su lugar ser manejado por un enrutador en la red).

+0

No es el primer lugar que se vería. ¿Cómo lo rompiste? –

+0

@ ThorbjørnRavnAndersen: No sabría cómo buscar esto ahora, pero hace unos 8 años '/ proc/slabinfo' tenía una entrada separada para las entradas" vecino "(por ejemplo, ARP). Cuando obtuviste 'ENOBUFS' solo mirabas' slabinfo' para ver qué almacenamientos intermedios eran. En la actualidad, probablemente se haya fusionado con algunas de las entradas de 'kmalloc-size'. – ninjalj

0

Tengo este error cuando intenté ejecutar un clúster de coherencia en dos JVM locales usando la conexión WIFI a la base de datos .. Si lo ejecuto usando ethernet, funciona bien.

Cuestiones relacionadas