2010-02-11 3 views
10

J'ai (le dernier en date) jdk 1.6.0.18 plantant lors de l'exécution d'une application web sur (le dernier en date) tomcat 6.0.24 de manière inattendue après 4 à 24 heures 4 heures à 8 jours de tests de stress (30 threads frapper l'application à 6 millions de pages vues/jour). C'est sur RHEL 5.2 (Tikanga).JVM se bloque sous tension sur RHEL 5.2

Le rapport d'accident est à http://pastebin.com/f639a6cf1 et les cohérentes parties de l'accident sont:

  • SIGSEGV est jeté
  • sur libjvm.so
  • espace eden est toujours plein (100%)

machine virtuelle Java fonctionne avec les options suivantes:

CATALINA_OPTS="-server -Xms512m -Xmx1024m -Djava.awt.headless=true" 

J'ai également testé la mémoire pour des problèmes matériels en utilisant http://memtest.org/ pendant 48 heures (14 passages de toute la mémoire) sans aucune erreur.

J'ai activé -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps pour inspecter les tendances du GC ou l'épuisement de l'espace, mais il n'y a rien de suspect là-bas. GC et GC complet se produit à des intervalles prévisibles, libérant presque toujours la même quantité de capacités de mémoire.

Mon application n'utilise directement aucun code natif.

Des idées d'où je devrais regarder ensuite?

Edition - plus d'info:

1) Il n'y a pas vm client dans ce JDK:

[[email protected] ~]$ java -version -server 
java version "1.6.0_18" 
Java(TM) SE Runtime Environment (build 1.6.0_18-b07) 
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode) 

[[email protected] ~]$ java -version -client 
java version "1.6.0_18" 
Java(TM) SE Runtime Environment (build 1.6.0_18-b07) 
Java HotSpot(TM) 64-Bit Server VM (build 16.0-b13, mixed mode) 

2) Modification de l'O/S est impossible.

3) Je ne veux pas modifier les variables de test de stress JMeter car cela pourrait cacher le problème. Depuis que j'ai un cas d'utilisation (le scénario de test de stress actuel) qui bloque la JVM, je voudrais réparer le crash et ne pas changer le test.

4) J'ai fait static analysis sur mon application mais rien de sérieux n'est apparu.

5) La mémoire ne s'allonge pas avec le temps. L'utilisation de la mémoire s'équilibre très rapidement (après le démarrage) selon une tendance très stable qui ne semble pas suspecte.

6)/var/log/messages ne contient pas d'informations utiles avant ou pendant le temps de l'accident

Plus d'info: Vous avez oublié de mentionner qu'il y avait un apache (2.2.14) fronting tomcat en utilisant mod_jk 1.2.28. En ce moment, je lance le test sans apache juste au cas où le crash JVM se rapporte au code natif mod_jk qui se connecte à JVM (connecteur tomcat). Après cela (si JVM se bloque à nouveau), je vais essayer de supprimer certains composants de mon application (mise en cache, lucene, quartz) et plus tard j'essaierai d'utiliser jetty. Étant donné que l'accident se produit actuellement entre 4 heures et 8 jours, cela peut prendre beaucoup de temps pour savoir ce qui se passe.

+1

Cela doit aller à Sun Oracle. – bmargulies

+0

@bmargulies: C'est ce que j'ai d'abord pensé, mais ensuite je lis http://stackoverflow.com/questions/1353514/anyone-tried-submitting-hserr-files-to-sun – cherouvim

+1

En supposant que vous utilisez un JDK récent, avez-vous essayé d'étudier son comportement en temps réel avec VisualVM? Nous avons constaté qu'il est beaucoup plus efficace que les profils de tiers pour enquêter sur les fuites. – Uri

Répondre

4

Avez-vous une sortie de compilation? c'est-à-dire PrintCompilation (et si vous vous sentez particulièrement courageux, LogCompilation). J'ai débogué un cas comme celui-ci dans la pièce en regardant ce que le compilateur fait et, finalement (cela a pris du temps jusqu'au moment de l'ampoule), j'ai réalisé que mon crash était causé par la compilation d'une méthode particulière le pilote oracle jdbc.

Fondamentalement ce que je ferais est;

  • interrupteur sur PrintCompilation
  • , car cela ne donne pas horodatages, écrire un script qui surveille que logfile (comme un sommeil chaque seconde et imprimer de nouvelles lignes) et des rapports lorsque les méthodes ont été compilées (ou non)
  • répéter le test de vérification
  • la sortie du compilateur pour voir si l'accident correspond à la compilation d'une méthode
  • répétition quelques fois pour voir s'il y a un modèle

S'il existe un motif discernable, utilisez .hotspot_compiler (ou .hotspotrc) pour l'empêcher de compiler la ou les méthodes incriminées, répétez le test et vérifiez s'il ne se déclenche pas. Évidemment, dans votre cas, ce processus pourrait théoriquement prendre des mois, j'en ai peur.

quelques références

L'autre chose que je voudrais faire est de changer systématiquement l'algorithme de gc vous utilisez et vérifier les temps de collision contre l'activité gc (par exemple est-ce corrélé avec un gc jeune ou vieux, qu'en est-il des TLAB?).Votre décharge indique que vous utilisez scavenge parallèle pour essayer

  • le collecteur de série (jeunes) (IIRC il peut être combiné avec un ancien parallèle)
  • ParNew + CMS
  • G1

si cela ne se reproduit pas avec les différentes algos GC alors vous savez que c'est à cela (et vous n'avez pas d'autre solution que de changer l'algo GC et/ou de revenir sur les anciennes JVM jusqu'à ce que vous trouviez une version de cet algo qui ne souffle pas).

+0

Merci d'avoir porté PrintCompilation à mon attention. Va certainement essayer ça. – cherouvim

3

quelques idées:

  • utiliser un JDK différent, Tomcat et/ou OS
  • modifier légèrement les paramètres de test, par exemple 25 fils de discussion à 7.2 M Pages vues/jour
  • utilisation de la mémoire du moniteur ou le profil
  • Debug ou régler le Garbage Collector
  • Exécuter une analyse statique et dynamique
1

Est-ce que votre mémoire au fil du temps? Croître Si c'est le cas, je suggère de changer les limites de la mémoire pour voir si le système échoue plus fréquemment lorsque la mémoire est épuisée.

Pouvez-vous reproduire le problème plus rapidement si:

  • vous réduisez la mémoire availble à la machine virtuelle Java?
  • Vous diminuez les ressources système disponibles (c'est-à-dire que la mémoire du système de vidange est insuffisante pour la machine virtuelle Java)
  • Vous remplacez vos cas d'utilisation par un modèle plus simple?

L'une des principales stratégies que j'ai utilisées est de déterminer quel cas d'utilisation est à l'origine du problème. Il peut s'agir d'un problème générique ou d'un cas d'utilisation spécifique. Essayez de consigner le début et l'arrêt des cas d'utilisation pour voir si vous pouvez déterminer quels cas d'utilisation sont les plus susceptibles de causer le problème. Si vous divisez vos cas d'utilisation en deux, voyez quelle moitié échoue le plus rapidement. Cela est susceptible d'être une cause plus fréquente de l'échec. Naturellement, exécuter quelques essais de chaque configuration augmentera la précision de vos mesures.

J'ai également été connu pour soit changer le serveur pour faire peu de travail ou faire une boucle sur le travail que fait le serveur. L'un fait que le code de votre application fonctionne beaucoup plus fort, l'autre rend le serveur Web et le serveur d'applications beaucoup plus difficiles.

Bonne chance, Jacob

+0

En regardant votre trace, la mémoire système ne devrait pas être le problème dans ce cas. Y a-t-il des messages dans le journal système? Aussi, si je le lis bien, il semblerait que vous ayez un nombre plutôt élevé de threads en cours d'exécution. Il y a une tonne de threads qui attendent le CPU disponible à un moment donné. Je m'attendrais à des temps de réponse moyens plus rapides avec un plus petit nombre de threads. – TheJacobTaylor

1

Essayez de mettre votre conteneur de servlet Tomcat de la jetée à http://jetty.codehaus.org/jetty/.

+0

Pour voir si la JVM va toujours planter? Ou pour une migration complète vers la jetée? – cherouvim

+0

J'irais faire une migration complète vers Jetty, juste parce que j'aime ce que j'ai vu de Jetty dans le passé. Cependant les dernières comparaisons que je viens de googler, semblent montrer que la performance de Jetty-6 vs Tomcat-6 sont assez égales, bien que Jetty a l'impression d'avoir une empreinte mémoire plus légère. D'une approche plus méthodique, tant que votre application est conforme aux normes, la migration ne doit pas être trop difficile, et vous pouvez alors éliminer le conteneur comme cause principale ou vérifier que votre application est la cause première. Bonne chance. – crowne

+1

merci pour le commentaire. Mon application est compatible avec tous les principaux serveurs (tomcat, jboss, résine, jetée, glashfish) donc la migration ne pose aucun problème. Je vais certainement essayer le test de stress sur la jetée. – cherouvim

1

Si je vous étais, je ferais ce qui suit:

  • essayer un peu les anciennes versions Tomcat/JVM. Vous semblez courir le plus récent et le plus grand. Je voudrais descendre deux versions ou plus, peut-être essayer JRockit JVM.
  • effectuez un vidage de thread (kill -3 java_pid) pendant que l'application s'exécute pour voir les piles complètes. Votre vidage actuel montre beaucoup de threads bloqués - mais on ne sait pas où ils bloquent (I/O? Une certaine famine interne de verrouillage? Quelque chose d'autre?). Je pourrais même programmer kill -3 pour être exécuté toutes les minutes afin de comparer n'importe quel vidage aléatoire avec celui juste avant le crash.
  • J'ai vu des cas où Linux JDK vient de mourir alors que Windows JDK est capable d'attraper une exception (alors StackOverflowException), donc si vous pouvez modifier le code, ajoutez "catch Throwable" quelque part dans la classe supérieure. Au cas où.
  • Jouer avec les options d'accord du GC. Activez/désactivez GC simultané, ajustez NewSize/MaxNewSize. Et oui, ce n'est pas scientifique - besoin désespéré de solution de travail.Plus de détails ici: http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

Dites-nous comment cela a été réglé!

2

Avez-vous essayé différents matériels? Il semble que vous utilisiez une architecture 64 bits. Dans ma propre expérience, 32 bits est plus rapide et plus stable. Peut-être qu'il y a un problème de matériel quelque part aussi. Le timing de "entre 4-24 heures" est assez étalé pour être juste un problème logiciel. Bien que vous disiez que le journal système n'a pas d'erreurs, je pourrais être loin. Toujours pense que ça vaut le coup d'essayer.

+0

Essayer un matériel différent n'est pas une option, mais je vais essayer le 32 bits jvm. Merci – cherouvim

1

Est-ce une option d'aller à la JVM 32 bits à la place? Je crois que c'est l'offrande la plus mature de Sun.

+0

va essayer cela. Merci. – cherouvim