10
votes

Java TCP / Problème de performance de la prise IP

Notre application est de lire des données très rapides sur les prises TCP / IP en Java. Nous utilisons la bibliothèque Nio avec des prises non bloquantes et un sélecteur pour indiquer la préparation à la lecture. En moyenne, les temps de traitement globaux pour la lecture et la gestion des données de lecture sont sous-millisecondes. Cependant, nous voyons fréquemment des pics de 10 à 20 millisecondes. (en cours d'exécution sur Linux).

Utilisation tcpdump Nous pouvons voir la différence de temps entre la lecture de TCPDump de 2 messages discrètes et la comparaison avec notre temps d'applications. Nous voyons tcpdump semble avoir aucun délai, alors que l'application peut afficher 20 millisecondes.

Nous sommes à peu près sûr que ce n'est pas GC, car le journal GC affiche pratiquement aucun GC complet, et dans JDK 6 (à partir de ce que je comprends), le GC par défaut est parallèle, il ne faut donc pas mettre en pause les threads d'application (sauf si GC complet).

Il semble presque comme s'il y a un délai pour le sélecteur de Java.Select (0) pour renvoyer la préparation à la lecture, car à la couche TCP, les données sont déjà disponibles pour être lues ( et tcpdump le lit).

Info supplémentaire: à la charge maximale, nous traitons environ 6 000 x 150 octets avg par message, soit environ 900 Mo par seconde.


5 commentaires

Comme @jim Lewis a dit, il est probable qu'une perte de temps au changement de contexte, et vous ne pouvez pas contrôler comment Java implémente Nio en interne. Il est tout à fait possible que la JVM ajoute quelques frais généraux que vous ne pourrez pas éliminer. Cela dit, sans voir plus de données, je ne peux pas vraiment offrir une solution.


Eh bien, j'ai nettoyé mes réponses inacceptées. Je ne veux pas que quiconque pense que je n'ai pas valorisé le temps qu'ils ont pris pour répondre à la question.


Je pourrais vous aider à donner quelques détails sur JVM, KEnel / Distro, Quincaillerie


@Matt: O / S = Linux Red Hat Enterprise 5.4, Version du noyau = 2,6, JVM = Java (TM) SE Environnement (Build 1.6.0_06-B02) - Serveur de serveur Java Hotspot (TM) (Build 10.0-B22, mélangé MODE), NIC: NIC: 01: 00.0 Contrôleur Ethernet: Broadcom Corporation Netxtreme II BCM5709 Gigabit Ethernet (REV 20), Vitesse du réseau = 1 GBS Full Duplex.


@Sam: cette information devrait aller dans votre question.


4 Réponses :


3
votes

Votre code Java est-il exécuté sous RTLinux ou une autre distribution avec une capacité de planification en temps réel? Sinon, 10-20 ms de gigue dans les temps de traitement semble totalement raisonnable et attendue.


5 commentaires

Je ne m'attendrais pas à une gigue de 10 à 20 ms pour une boîte moderne qui n'est pas sérieusement surchargée, même quelques 00 00 00.


@Matt: Comme je le comprends, 10 ms est une valeur typique de la longueur d'une franchise de temps dans un planificateur à temps non réel Linux / X86. Donc, si l'appel SELECT () donne la CPU, cela pourrait facilement prendre ce travail pour que ce travail soit à nouveau planifié.


J'essaie de comprendre votre commentaire - nous exécutons Red Hat Enterprise 5.4. 2 cpus. La machine est principalement occupée en exécution de l'application Java et MySQL. Désactiver la mise à jour de la base de données ou d'autres processus sur le serveur semble avoir aucun impact sur les pics de latence. Pensez-vous potentiellement que nous pouvons résoudre ce problème en passant à une distribution RTLinux.


AFAIK Le planificateur de Linux actuel (CFS) n'est pas tranchée de temps, certains détails ici Donc, je ne crois pas que vous puissiez assumer des interruptions de 100Hz signifie le réveil sur les limites de 10 ms. Cela pourrait signifier une résolution 10 ms à certains horodatages que vous souhaitez.


@Sam: Il est possible que la commutation sur RTLinux vous donne plus de contrôle sur cette latence, oui. Difficile de dire à coup sûr, mais votre latence de 10-20 ms est sûre que vous sonnez comme une planification de la gigue ... mais je ne connais pas de choses plus modernes comme cfs. Il peut être possible de réduire la latence en réglant les paramètres de planification et les priorités de processus, sans recourir à un système d'exploitation RT complet. En outre, la remarque de Matt sur la résolution de l'horodatage vaut la peine d'être envisagée.



1
votes

à partir du FAQ TCPDump :

Quand est-ce qu'un paquet est tamponné? COMMENT Précis sont les horaires?

Dans la plupart des OSES sur lesquels Tcpdump et Libpcap courir, le paquet est le temps estampillé dans le cadre du processus du Pilote de périphérique d'interface réseau, ou la pile de réseau, la manipulation. Cela signifie que le paquet n'est pas le temps estampillé à l'instant qu'il arrive à l'interface réseau; après le Le paquet arrive sur le réseau interface, il y aura un retard jusqu'à ce que une interruption est livrée ou la interface réseau est interrogé (c'est-à-dire le L'interface réseau peut ne pas interrompre l'hôte immédiatement - le conducteur peut être mis en place pour interroger l'interface si Le trafic réseau est lourd, afin de réduire le nombre d'interruptions et de processus plus de paquets par interruption), et là sera un autre retard entre le point auquel l'interruption commence être traité et l'horodatage est généré.

Donc, l'horodatage est effectué dans la couche de noyau privilégié, et les 20 ms perdus sont de passer au-dessus de la tête de dépassement de l'espace utilisateur et de Java et de la logique de sélecteur de réseau JVMS. Sans plus d'analyse du système dans son ensemble, je ne pense pas qu'il soit possible de faire une sélection affirmative de cause.


2 commentaires

Parlait de votre réponse avec d'autres gars de notre bureau. Ils ont souligné que les pics que nous voyons sont jusqu'à 40 ms. différence de TCPDump. Cela semble être trop important d'une différence à expliquer par ce qui précède. C'est vraiment le comportement "Spik" incompatible que nous essayons de réparer.


Êtes-vous certain que vous avez éliminé les opérations de GC comme une cause? Quel pourcentage de demandes entraînent une "pic"?



4
votes

La collection Eden encourt toujours une pause STW de sorte que 20ms peut être parfaitement normale en fonction du comportement d'allocation et de la taille du tas / la taille du jeu en direct.


2 commentaires

Après beaucoup plus de test, de profilage, etc. Nous avons conclu que GC, même GC mineur utilisant ParalLelgc semble tout arrêter. Les pauses vont de 2 ms à 20 ms. Faire le code plus efficace pourrait réduire le nombre de cycles de GC et peut-être même le temps de GC. Cela affecte donc une latence des communications de socket, et il semble que rien ne puisse être fait. Nous avons testé RTLinux, et donc aucune amélioration majeure. Nous avons commencé à étudier le Java en temps réel, mais je ne pensais pas que c'était la meilleure avenue (coûts sage et complexité-sage).


La plupart des CMS sont en parallèle. Il n'y a qu'une très petite partie STW .. qui semble être les 20ms que vous voyez (vous pouvez l'attacher à des journaux GC). Si vous souhaitez des pauses prévisibles, vous pouvez consulter le collecteur G1, mais vous aurez plus de pauses globales que le CMS.



2
votes

J'ai eu le même problème dans un service Java que je travaille sur. Lors de l'envoi de la même demande À plusieurs reprises du client, le serveur bloquerait au même endroit dans le flux de 25-35ms. Désactivez l'algorithme de Nagle dans la prise, résolue cela pour moi. Cela peut être accompli en appelant SetCPnodelay (true) sur la prise. Cela peut entraîner une augmentation de la congestion du réseau car les ACKS seront désormais envoyés comme séparés. paquets. Voir http://fr.wikipedia.org/wiki/nagle%27s_algorithm pour plus d'informations sur l'algorithme de Nagle.


0 commentaires