2009-06-25 5 views
5

J'ai un composant tiers qui essaie d'envoyer trop de messages UDP à trop d'adresses distinctes dans une certaine situation. C'est une rafale qui survient lorsque le logiciel est démarré et que la situation est temporaire. Je ne suis pas sûr que ce soit le montant des messages ou le fait que chacun d'entre eux aille à une adresse IP distincte.Java IOException: aucun espace tampon disponible lors de l'envoi de paquets UDP sous Linux

Quoi qu'il en soit, la modification du protocole sous-jacent ou le composant problématique n'est pas une option, donc je suis à la recherche d'une solution de contournement. Le StackTrace ressemble à ceci:

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

Ce problème se produit (au moins) avec les versions Java 1.6.0_13 et 1.6.0_10 et versions Linux Ubuntu 9.04 et RHEL 4.6. Y a-t-il des propriétés système Java ou des réglages de configuration Linux qui pourraient vous aider?

Répondre

3

Lors de l'envoi de nombreux messages, notamment sur Gigabit ethernet sous Linux, les paramètres de stock pour votre noyau ne sont généralement pas optimaux. Vous pouvez augmenter la taille du tampon du noyau Linux pour la mise en réseau à travers:

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 

En tant que racine.

Ou utilisez sysctl

sysctl -w net.core.rmem_max=8388608 

Il y a des tonnes d'options de réseau

Affichez Linux Network Tuning by IBM et More tuning information

+0

Merci. En plus de ces paramètres, j'ai essayé de modifier net.ipv4.udp_mem et net.ipv4.udp_wmem_min. D'abord j'ai doublé, les valeurs, puis je les ai doublées encore, et finalement je les ai changées pour qu'elles soient 10 fois plus grosses que les valeurs par défaut. Rien n'a aidé jusqu'à présent. – auramo

+0

@auramo, Quelle JVM utilisez-vous? Le soleil construit ou les trucs OpenJDK/JVM de votre distribution? Je recommanderais d'en utiliser un pour votre distribution, le plus ouvert si possible car il sera moins sûr et plus précis avec le noyau/libc. –

+0

J'utilise les versions Sun de 1.6.0_13 et 1.6.0_10. Je pourrais facilement essayer avec les versions d'OpenJDK, mais en changeant de l'implémentation de Sun, l'OpenJDK pour le produit final serait un problème majeur à ce stade du projet. – auramo

1

peut-être un peu compliqué mais comme je sais, Java utilise le SPI modèle pour la sous-bibliothèque réseau. Cela vous permet de modifier l'implémentation utilisée pour diverses opérations réseau. Si vous utilisez OpenJDK, vous pouvez obtenir quelques conseils sur comment et comment mettre en place votre implémentation. Ensuite, dans votre implémentation, vous ralentissez les E/S avec des sleeps par exemple. Ou, juste pour le plaisir, vous pouvez remplacer le DatagramSocket par défaut avec votre mise en œuvre modifiée. Ayez le même nom de paquet et - comme je le sais - il aura préséance sur la classe JRE par défaut. Au moins, cette méthode a fonctionné pour moi sur une bibliothèque buggy 3rd party.

Edit:

Interface fournisseur de services est une méthode pour séparer le code client et de service au sein d'une API. Cette séparation permet différentes implémentations client et différentes. Peut être reconnu à partir du nom se terminant par Impl généralement, tout comme dans la trace de votre pile java.net.PlainDatagramSocketImpl est l'implémentation du fournisseur où DatagramSocket est l'API côté client.

Vous avez commenté que vous ne voulez pas ralentir la communication tout le chemin. Il ya plusieurs hacks pour l'éviter, par exemple mesurer l'heure dans votre code et ralentir la communication dans les 1-2 premières minutes à partir de votre premier appel de méthode entrant. Ensuite, vous pouvez passer le sommeil.

Une autre option consisterait à identifier la classe se conduisant mal dans la bibliothèque, JAD et corrigez-la. Puis remplacez le fichier de classe d'origine dans la bibliothèque.

+0

Pouvez-vous me dire ce qu'est un modèle SPI? Je veux surmonter une rafale de 1-2 minutes, au démarrage. Pour cela, je ne veux surtout pas ralentir mon E/S UDP qui doit être rapide tout au long de l'application (c'est une application serveur). – auramo

+0

Ok, ce vieux modèle :-) – auramo

0

Je suis également actuellement voir ce problème aussi bien avec Debian & RHEL. À ce stade, je crois que je l'ai isolé à la carte réseau et/ou le pilote NIC. Quelle configuration matérielle avez-vous cela présente également ce problème? Cela semble se produire uniquement sur les nouveaux serveurs Dell PowerEdge que nous avons récemment acquis et qui possèdent des cartes réseau Gigabit Ethernet NetXtreme II BCM5708 de Broadcom Corporation.

Je peux aussi confirmer que c'est la génération rapide de paquets UDP sortants vers de nombreuses adresses IP différentes dans une courte fenêtre. J'ai essayé d'écrire une application Java simple qui peut le reproduire (puisque la nôtre se produit avec snmp4j).

EDIT

Regardez ma réponse ici: Java IOException: No buffer space available while sending UDP packets on Linux

+0

Mon problème est survenu sur de nombreuses configurations hw, sur un poste de travail HP ainsi que sur un serveur rack. Finalement, nous avons fini par pirater le composant sous-jacent (composant Java d'une autre équipe au sein de notre société), ce qui a provoqué une surcharge de la messagerie réseau. Maintenant, ce composant fait beaucoup moins de demandes/réponses UDP et le problème est résolu pour nous. – auramo

7

J'ai finalement déterminé ce que la question est. L'exception Java IOException est trompeuse car il n'y a pas d'espace tampon disponible, mais le problème principal est que la table ARP locale a été remplie. Sous Linux, la recherche de table ARP par défaut est 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). Ce qui se passait dans mon cas (et je suppose que c'est votre cas), c'est que votre code Java envoie des paquets UDP à partir d'une adresse IP qui se trouve dans le même sous-réseau que vos adresses de destination. Lorsque c'est le cas, la machine Linux effectuera une recherche ARP pour traduire l'adresse IP en adresse MAC matérielle. Comme vous envoyez des paquets à de nombreux IP différents, la table ARP locale se remplit rapidement, frappe 1024, et c'est là que l'exception Java est levée. La solution est simple, soit augmenter la limite en éditant les fichiers que j'ai mentionnés précédemment, ou déplacer votre serveur dans un sous-réseau différent de vos adresses de destination, ce qui amène la machine Linux à ne plus effectuer les recherches ARP voisines (à la place être géré par un routeur sur le réseau).

+0

Pas le premier endroit que l'on aurait l'air. Comment l'avez-vous craqué? –

+0

@ ThorbjørnRavnAndersen: Je ne saurais pas comment le rechercher maintenant, mais il y a 8 ans '/ proc/slabinfo' avait une entrée séparée pour les entrées" neigh "(par exemple ARP). Quand vous avez 'ENOBUFS' vous avez juste regardé' slabinfo' pour voir quels tampons étaient. De nos jours, il est probablement fusionné avec certaines des entrées 'kmalloc-size'. – ninjalj

0

J'ai cette erreur quand j'ai essayé d'exécuter le cluster de cohérence dans deux JVM locales en utilisant la connexion WIFI à la base de données .. Si je l'exécute en utilisant l'Ethernet - il fonctionne bien.

Questions connexes