Java, en tant que langage, a été conçu pour rendre impossible qu'un code développé par l'utilisateur provoque un plantage de l'application. Toute erreur devait se traduire par le lancement d'une exception propre et nette, qui pouvait être interceptée, puis traitée de manière appropriée. La réalité, comme le savent tous les développeurs Java de longue date ou les administrateurs système, est que la machine virtuelle Java (JVM) elle-même peut planter, et plante effectivement. Cela s'explique par le fait que la JVM est elle-même un programme écrit en code natif et que, comme tout programme très volumineux et complexe, la JVM contient quelques bogues.

Comme n'importe quel programme, lorsque Java plante, il meurt simplement et disparaît, emportant votre application avec lui. Cela peut être désastreux si l'application est un système critique. L'application sera hors service, et la panne peut ne pas être remarquée avant qu'un client ne visite votre site Web, ou que le service des expéditions n'appelle parce qu'il n'a reçu aucune commande d'expédition depuis quelques heures. Une fois que l'arrêt de l'application a été détecté, il peut encore s'écouler une heure ou deux avant que l'administrateur système n'intervienne pour la redémarrer.

Solution

La solution à ce problème consiste à disposer d'une application de surveillance, possédant une connaissance approfondie du fonctionnement de Java. Elle doit être suffisamment fiable pour surveiller votre application Java 24 heures sur 24, 365 jours par an, et prendre automatiquement en charge les problèmes lorsqu'ils surviennent. Le Java Service Wrapper contient plusieurs fonctionnalités de surveillance, dont la capacité à détecter lorsqu'une JVM a planté. Il surveille constamment la JVM et est capable de reconnaître instantanément lorsqu'elle a planté. Dès qu'un plantage est détecté, le Java Service Wrapper redémarre automatiquement la JVM afin de remettre le système en service avec un minimum de délai. Enfin, vous pouvez configurer une notification par e-mail à envoyer à l'administrateur système afin de s'assurer que tout est de nouveau opérationnel.

L'ensemble du processus de détection des plantages, de récupération et de notification est entièrement géré par le Java Service Wrapper automatiquement, sans qu'un opérateur humain n'ait besoin d'intervenir. Lorsqu'un plantage est détecté, le Java Service Wrapper enregistrera quelque chose comme ce qui suit dans le fichier journal :

Exemple de journal : plantage et redémarrage :
jvm 1    | ...
jvm 1    | #
jvm 1    | # A fatal error has been detected by the Java Runtime Environment:
jvm 1    | #
jvm 1    | #  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000001800074ff, pid=856, tid=704
jvm 1    | #
jvm 1    | # JRE version: 6.0_24-b07
jvm 1    | # Java VM: Java HotSpot(TM) 64-Bit Server VM (19.1-b02 mixed mode windows-amd64 compressed oops)
jvm 1    | # Problematic frame:
jvm 1    | # C  [wrapper.dll+0x74ff]
jvm 1    | #
jvm 1    | # An error report file with more information is saved as:
jvm 1    | # C:\myapp\bin\hs_err_pid856.log
jvm 1    | #
jvm 1    | # If you would like to submit a bug report, please visit:
jvm 1    | #   http://java.sun.com/webapps/bugreport/crash.jsp
jvm 1    | # The crash happened outside the Java Virtual Machine in native code.
jvm 1    | # See problematic frame for where to report the bug.
jvm 1    | #
wrapper  | JVM exited unexpectedly.
wrapper  | Launching a JVM...
jvm 2    | WrapperManager: Initializing...
jvm 2    | ...

Bien que le message ci-dessus puisse sembler un peu cryptique, il s'agit de la tentative de la JVM de vous fournir des informations sur le plantage. Comme cette sortie est envoyée vers la console à un niveau très bas par la JVM, il est impossible pour tout outil de journalisation basé sur Java d'enregistrer ces informations. Notez que le Wrapper est capable de capturer 100 % de la sortie console de la JVM et de s'assurer que le tout est conservé dans le fichier journal. Sans le Wrapper, non seulement votre application resterait hors service, mais l'explication de ce qui s'est passé serait également perdue.

Idéalement, tout plantage devrait être corrigé dès que possible afin d'éviter de futurs plantages. Cependant, comme de nombreux plantages sont causés par des interactions obscures entre du code Java parfaitement valide et des bogues dans la JVM elle-même, il peut souvent falloir des semaines ou des mois aux développeurs pour identifier le problème et le contourner.

Le Wrapper vous aide à détecter les problèmes critiques, notamment :

Présentation technique

La détection des plantages dans le Wrapper est toujours activée, car la vérification des plantages n'impose aucune charge supplémentaire à la JVM ou au système. Comme les plantages se produisent ou non, il n'existe aucun moyen de désactiver leur détection. Il est toutefois possible de contrôler ce que fait le Wrapper lorsqu'un plantage se produit.

Lorsqu'un plantage est détecté, le Wrapper attendra d'abord un moment (5 secondes par défaut) afin de permettre à la mémoire et aux ressources système de revenir à la normale, puis, après toute notification configurée, lancera une nouvelle instance de JVM pour remettre votre application en service sans délai. Comme décrit ci-dessous, il est possible de désactiver cette fonctionnalité de redémarrage automatique si nécessaire.

Essayer

Espérons que vous aurez du mal à reproduire un plantage de JVM dans votre propre application Java. Pour faciliter les tests, le Wrapper est livré avec une application d'exemple TestWrapper qui peut être utilisée pour essayer cette fonctionnalité ainsi que de nombreuses autres.

Veuillez lancer l'application TestWrapper depuis une console en vous rendant dans la distribution Java Service Wrapper téléchargée et décompressée. Sous Windows, exécutez bin\TestWrapper.bat et sur les plates-formes UNIX, exécutez bin\testwrapper console.

Lorsque l'application d'exemple TestWrapper démarre, vous devriez voir un écran d'interface graphique simple avec plusieurs boutons sur le côté gauche. Un clic sur le bouton Native Access Violation fera apparaître la JVM comme plantée au Wrapper.

Exemple de journal : plantage et redémarrage.
jvm 1    | TestWrapper: Showing dialog...
jvm 1    | WrapperManager: WARNING: Attempting to cause an access violation...
jvm 1    | #
jvm 1    | # A fatal error has been detected by the Java Runtime Environment:
jvm 1    | #
jvm 1    | #  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000018000746f, pid=1632, tid=2284
jvm 1    | #
jvm 1    | # JRE version: 6.0_24-b07
jvm 1    | # Java VM: Java HotSpot(TM) 64-Bit Server VM (19.1-b02 mixed mode windows-amd64 compressed oops)
jvm 1    | # Problematic frame:
jvm 1    | # C  [wrapper.dll+0x746f]
jvm 1    | #
jvm 1    | # An error report file with more information is saved as:
jvm 1    | # C:\myapp\bin\hs_err_pid856.log
jvm 1    | #
jvm 1    | # If you would like to submit a bug report, please visit:
jvm 1    | #   http://java.sun.com/webapps/bugreport/crash.jsp
jvm 1    | # The crash happened outside the Java Virtual Machine in native code.
jvm 1    | # See problematic frame for where to report the bug.
jvm 1    | #
wrapper  | JVM exited unexpectedly.
wrapper  | Launching a JVM...
jvm 2    | WrapperManager: Initializing...

Si vous souhaitez tester cela dans votre propre application Java, il est possible d'appeler la méthode WrapperManager.accessViolationNative() pour provoquer un plantage intentionnel.

Dépannage

Les rapports de plantage de Java peuvent, à première vue, ne pas sembler très utiles. Mais lorsque vous savez ce qu'il faut rechercher, ils peuvent vous fournir des informations très utiles nécessaires pour résoudre le problème.

Dans l'exemple ci-dessus, la JVM nous indique qu'un rapport d'erreur détaillé a été enregistré sur le disque sous C:\myapp\bin\hs_err_pid856.log. L'analyse de ces rapports de plantage dépasse le cadre de ce document, mais nous vous recommandons de consulter le Guide de dépannage sur le site d'Oracle. Si vous voulez vraiment mettre les mains dans le cambouis, alors ce cours accéléré sur l'analyse des plantages de JVM est également assez utile.

Délai de redémarrage

Compatibilité :2.2.9
Éditions :Édition ProfessionnelleÉdition StandardÉdition Community
Plateformes :WindowsMac OSXLinuxAlpine LinuxFreeBSDSolarisIBM z/Linux

Lorsqu'un plantage est détecté, le Wrapper attendra par défaut 5 secondes afin de permettre à la mémoire et aux ressources système qui étaient utilisées par la JVM plantée d'être récupérées par le système, avant de lancer une JVM de remplacement. Si une nouvelle JVM est lancée trop rapidement, selon les raisons du plantage, la nouvelle JVM peut rencontrer des problèmes ou démarrer lentement.

Le temps nécessaire au système pour se stabiliser dépend de plusieurs facteurs, notamment la charge globale du système et la taille de l'application qui s'exécutait dans la JVM plantée. Bien qu'il soit possible de raccourcir ce délai, la valeur par défaut s'est avérée être un temps d'attente sûr. Le délai avant le redémarrage d'une nouvelle JVM peut être contrôlé à l'aide de la propriété wrapper.restart.delay.

Exemple de configuration : temps d'attente avant le redémarrage de la JVM (5 secondes)
wrapper.restart.delay=5

Désactivation des redémarrages

Compatibilité :3.3.4
Éditions :Édition ProfessionnelleÉdition StandardÉdition Community
Plateformes :WindowsMac OSXLinuxAlpine LinuxFreeBSDSolarisIBM z/Linux

Dans la plupart des cas, lorsqu'une JVM plante, vous voudrez qu'elle soit redémarrée. Il existe cependant certains cas où un nettoyage manuel ou d'autres actions peuvent être nécessaires au préalable. Dans ces cas, la fonctionnalité de redémarrage du Wrapper peut être désactivée à l'aide de la propriété wrapper.disable_restarts.automatic.

Exemple de configuration : (Désactiver le redémarrage)
wrapper.disable_restarts.automatic=TRUE

Réagir aux événements

Compatibilité :3.3.0
Éditions :Édition ProfessionnelleÉdition Standard (non prise en charge)Édition Community (non prise en charge)
Plateformes :WindowsMac OSXLinuxAlpine LinuxFreeBSDSolarisIBM z/Linux

Parfois, lorsqu'une application se fige ou plante, il ne suffit pas toujours de la redémarrer simplement. Si des fichiers temporaires n'ont pas été correctement nettoyés, ou si la base de données a été laissée dans un état instable, la nouvelle instance de l'application peut rapidement échouer avec des erreurs. Idéalement, l'application devrait être conçue pour être suffisamment robuste afin de gérer ces défaillances, mais ce n'est pas toujours possible. Dans de tels cas, nous avons besoin d'un moyen d'effectuer un nettoyage avant de lancer une nouvelle JVM.

Le Wrapper prend cela en charge grâce à l'utilisation des commandes d'événements. Il est possible de demander au Wrapper d'exécuter une commande ou un script externe à divers moments.

Si vous consultez la sortie du journal de débogage, vous verrez occasionnellement des entrées Enqueue Event 'NNN'. Celles-ci indiquent le moment où les événements du Wrapper sont déclenchés. Dans le cas des redémarrages après la détection d'une JVM figée, nous voulons lancer notre script de nettoyage avant que la nouvelle instance de JVM ne soit lancée. L'événement jvm_restart sera utilisé.

Veuillez créer un fichier batch simple comme suit et le placer dans le même répertoire que le binaire du Wrapper. Cet exemple simule simplement une tâche de nettoyage de 10 secondes. Un script réel serait plus intéressant.

Script d'exemple : « cleanupTest.bat »
@echo off
echo Cleaning up for 10 seconds...
rem use ping to cause a 10 second delay.
PING 1.1.1.1 -n 1 -w 10000 >NUL
echo All done cleaning up.

Ajoutez ensuite les propriétés suivantes à votre wrapper.conf

Fichier de configuration : « wrapper.conf »
wrapper.event.jvm_restart.command.argv.1=cleanupTest.bat
wrapper.event.jvm_restart.command.block=TRUE
wrapper.event.jvm_restart.command.loglevel=INFO

Désormais, lorsqu'un gel est détecté, le Wrapper exécutera le fichier batch configuré et se bloquera jusqu'à ce qu'il soit terminé :

Exemple de sortie du journal
jvm 1    | # The crash happened outside the Java Virtual Machine in native code.
jvm 1    | # See problematic frame for where to report the bug.
jvm 1    | #
wrapper  | JVM exited unexpectedly.
wrapper  | Event Command 'jvm_restart': Command line: cleanupTest.bat
wrapper  | Event Command 'jvm_restart': Command launched (pid: 965), blocking for up to 15 seconds...
Cleaning up for 10 seconds...
All done cleaning up.
wrapper  | Event Command 'jvm_restart': Command completed with exit code: 0
wrapper  | Event Command 'jvm_restart': Command completed with exit code: 0  Continuing.
wrapper  | Launching a JVM...

Notification par e-mail

Compatibilité :3.3.0
Éditions :Édition ProfessionnelleÉdition Standard (non prise en charge)Édition Community (non prise en charge)
Plateformes :WindowsMac OSXLinuxAlpine LinuxFreeBSDSolarisIBM z/Linux

En plus de la possibilité de lancer des commandes externes en réponse à un événement de gel, il est également possible de configurer le Wrapper pour envoyer un e-mail de notification. L'e-mail peut prendre la forme d'un simple avis, ou éventuellement inclure la sortie de journal la plus récente en pièce jointe.

Une notification par e-mail de l'événement jvm_unexpected_exit peut être configurée comme suit :

Fichier de configuration « wrapper.conf »
wrapper.event.default.email.smtp.host=mail.example.com
wrapper.event.default.email.sender=wrapper-app@example.com
wrapper.event.default.email.recipient=sysadmin@example.com
wrapper.event.jvm_unexpected_exit.email=TRUE
wrapper.event.jvm_unexpected_exit.email.subject=Oh no! The application crashed!
wrapper.event.jvm_unexpected_exit.email.maillog=ATTACHMENT

Cela entraînera l'envoi d'un e-mail comme le suivant chaque fois que la JVM plante.

E-mail jvm_unexpected_exit
Subject: Oh no! The application crashed!.
To: sysadmin@example.com
From: wrapper-app@example.com

Java Service Wrapper Event Notification

Host: myserver
App Name: testwrapper
         TestWrapper Example Application

Event: jvm_unexpected_exit

INFO   | jvm 1    | 2012/09/13 16:00:00 | ...
INFO   | jvm 1    | 2012/09/13 16:00:00 | # The crash happened outside the Java Virtual Machine in native code.
INFO   | jvm 1    | 2012/09/13 16:00:00 | # See problematic frame for where to report the bug.
INFO   | jvm 1    | 2012/09/13 16:00:00 | #
ERROR  | wrapper  | 2012/09/13 16:00:00 | JVM exited unexpectedly.

Mais il est également bon de recevoir de bonnes nouvelles. La configuration suivante indiquera également au Wrapper d'envoyer un second e-mail chaque fois que la JVM a été lancée et que votre application est de nouveau opérationnelle. Cette paire d'e-mails peut être très utile pour vous tenir informé de l'état de votre serveur afin que vous puissiez décider s'il est acceptable de vous détendre et de profiter du reste du dîner.

Fichier de configuration « wrapper.conf »
wrapper.event.jvm_started.email=TRUE
wrapper.event.jvm_started.email.subject=Good news!  The applicaiton is back up.
wrapper.event.jvm_started.email.maillog=ATTACHMENT

Les systèmes d'e-mail et d'événements du Wrapper sont très puissants et configurables. Veuillez consulter la page Présentation des événements pour plus de détails.

Récupération du service

Compatibilité :3.5.5
Éditions :Édition ProfessionnelleÉdition StandardÉdition Community (non prise en charge)
Plateformes :WindowsMac OSX (Non pris en charge)Linux (Non pris en charge)Alpine Linux (Non pris en charge)FreeBSD (Non pris en charge)Solaris (Non pris en charge)IBM z/Linux (Non pris en charge)

Le Wrapper est responsable et pleinement capable de gérer tous les plantages Java. Bien que le processus Wrapper lui-même se soit avéré très stable, cette section explique comment récupérer d'un plantage du processus Wrapper lui-même.

Le Gestionnaire de services Windows est responsable du démarrage, de l'arrêt et de la surveillance de tous les services Windows, y compris le Wrapper. Il est possible de configurer le Wrapper pour indiquer au Gestionnaire de services Windows ce qu'il doit faire en cas de plantage du Wrapper. Ces fonctionnalités de récupération peuvent être configurées à l'aide des propriétés disponibles dans la section Récupération du service Windows. Veuillez consulter une procédure pas à pas pour un exemple de la propriété wrapper.ntservice.recovery.<x>.

Référence : Plantages

Le Java Service Wrapper fournit un ensemble complet de propriétés de configuration qui vous permettent d'adapter le Wrapper à vos besoins exacts. Veuillez consulter la documentation des propriétés individuelles pour découvrir toutes les possibilités au-delà des exemples présentés ci-dessus.