web-dev-qa-db-fra.com

Tomcat ne s'arrête pas. Comment puis-je déboguer cela?

J'ai un Tomcat 7 fonctionnant sous Linux que je démarre via $CATALINA_HOME/bin/startup.sh et arrêt via $CATALINA_HOME/bin/shutdown.sh
de /etc/init.d

Tout va bien sauf 1 problème. Parfois, Tomcat ne s'arrête pas.
Bien que je l'arrête et que je vois dans les journaux catalina.out qui descend, si je le fais ps -ef Je peux toujours voir le processus en cours.

Quel pourrait être le problème? Comment puis-je déboguer cela? Mon sentiment est que cela est lié aux fils.

Les parties suspectes sont donc les suivantes:
1) J'utilise LogManager de Log4j pour détecter si la configuration de log4j a été modifiée, mais je Log4jManager.shutdown sur un contextDestroyedServletContextListener
2) J'utilise H2 base de données et je vois à l'arrêt:

GRAVE: l'application Web [/ MyApplication] semble avoir démarré une
thread nommé [H2 Log Writer MYAPPLICATION] mais n'a pas pu l'arrêter.
Il y a beaucoup de chances que cela génère des fuites mémoires

GRAVE: l'application Web [/ MyApplication] semble avoir démarré une
thread nommé [H2 File Lock Watchdog
/opt/myOrg/Tomcat/webapps/MyApplication/db/myDatabase.lock.db] mais a
n'a pas réussi à l'arrêter. Il y a beaucoup de chances que cela génère des fuites mémoires. 2 avr.
2012 9:08:08 org.Apache.catalina.loader.WebappClassLoader
clearReferencesThreads SEVERE: L'application Web [/ MyApplication]
semble avoir démarré un thread nommé [FileWatchdog] mais a échoué
pour l'arrêter. Il y a beaucoup de chances que cela génère des fuites mémoires.

Vous avez besoin d'aide? Comment puis-je détecter le problème ici?

MISE À JOUR:
J'ai fait un kill -3 comme suggéré par @daveb, et dans le catalina.out je vois:

JVMDUMP006I Traitement de l'événement de vidage "utilisateur", détail "" - veuillez patienter. JVMDUMP032I JVM a demandé Java à l'aide de '/etc/init.d/javacore.20120402.093922.2568.0001.txt' en réponse à un événement JVMDUMP010I Java écrit dans /etc/init.d/javacore.20120402.093922.2568.0001.txt JVMDUMP013I Événement de vidage traité "utilisateur", détail "".

Il y a un javacore dans /etc/init.d mais je ne sais pas comment le traiter. C'est à dire. quelles parties dois-je étudier

32
Jim

Si l'application Web est arrêtée, toutes les connexions à la base de données doivent également être fermées. Si vous n'avez pas de liste de connexions, exécutez l'instruction SQL "shutdown" (cela ne fonctionne que pour les bases de données H2 et HSQLDB).

Si vous avez enregistré un servlet, vous pouvez le faire dans la méthode Servlet.destroy().

Si vous avez enregistré un ServletContextListener, vous pouvez exécuter l'instruction "shutdown" dans la méthode ServletContextListener.contextDestroyed(ServletContextEvent servletContextEvent). C'est quoi org.h2.server.web.DbStarterServletContextListener fait (celui qui est inclus dans la base de données H2).

4
Thomas Mueller

Découvrez quels threads sont toujours en cours d'exécution (ou bloqués, en attente d'exécution) en utilisant jstack ou en envoyant un signal au processus:

kill -3 pid

Lorsque vous savez cela, vous pouvez faire en sorte que ce qui les a démarrés se connecte à la notification d'arrêt pour arrêter les threads. Ou faites de ces fils des fils de démons.

Voir Cette question d'arrêt de Tomcat pour plus de détails à ce sujet.

Si vous ne savez pas où vos threads ont été créés, envisagez d'y ajouter des noms - les exécuteurs peuvent prendre des usines de threads, et vous pouvez utiliser ces usines pour définir le statut de démon d'un thread et aussi pour le nommer - afin que votre trace de pile soyez plus clair.

19
daveb

Vérifiez si votre application Web a un planificateur actif, comme Quartz.

Si vous ne l'arrêtez pas, le thread d'application Web ne se termine jamais jusqu'à ce que vous le tuiez

7
Marco

J'ai eu exactement le même problème. Parfois, la commande ./shutdown.sh n'arrête pas le processus Tomcat et son processus Java reste dans les processus en cours d'exécution.

J'avais résolu ce problème en utilisant la version Tomcat dans les dépôts de logiciels d'Ubuntu, en:

Sudo apt-get install Tomcat7

Après l'avoir installé à partir du gestionnaire de paquets et configuré certains paramètres, je n'ai eu aucun problème pour arrêter/démarrer Tomcat. J'ai utilisé cette commande pour arrêter, et elle n'a jamais échoué:

service Tomcat7 stop

ce qui est presque le même que

/etc/init.d/Tomcat7 stop

L'utilisation de cette commande exécute le bloc de code du script init, en particulier les codes du fichier /etc/init.d/Tomcat7. Je l'ai donc examiné pour voir ce que cela fait de toujours tuer le processus Tomcat avec succès. Voici le bloc de code qui s'exécute lorsque vous utilisez service Tomcat7 stop commande:

log_daemon_msg "Stopping $DESC" "$NAME"

        set +e
        if [ -f "$CATALINA_PID" ]; then
                start-stop-daemon --stop --pidfile "$CATALINA_PID" \
                        --user "$Tomcat7_USER" \
                        --retry=TERM/20/KILL/5 >/dev/null
                if [ $? -eq 1 ]; then
                        log_progress_msg "$DESC is not running but pid file exists, cleaning up"
                Elif [ $? -eq 3 ]; then
                        PID="`cat $CATALINA_PID`"
                        log_failure_msg "Failed to stop $NAME (pid $PID)"
                        exit 1
                fi
                rm -f "$CATALINA_PID"
                rm -rf "$JVM_TMP"
        else
                log_progress_msg "(not running)"
        fi
        log_end_msg 0
        set -e
        ;;

La partie importante est la suivante:

start-stop-daemon --stop --pidfile "$CATALINA_PID" \
                            --user "$Tomcat7_USER" \
                            --retry=TERM/20/KILL/5 >/dev/null

Cela signifie "réessayer l'arrêt jusqu'à ce que le processus soit arrêté. Voici la documentation de la commande --retry du manuel start-stop-daemon:

   -R|--retry timeout|schedule
          With  --stop,  specifies  that  start-stop-daemon  is  to  check
          whether  the  process(es)  do  finish.  It will check repeatedly
          whether any matching processes are running, until none are.   If
          the  processes  do  not exit it will then take further action as
          determined by the schedule.

          If timeout is specified instead of schedule  then  the  schedule
          signal/timeout/KILL/timeout  is used, where signal is the signal
          specified with --signal.
          ...

Alors, --retry=TERM/20/KILL/5 signifie "Envoyer TERME signal au processus, attendre 20 secondes, s'il est toujours en cours d'exécution, envoyer TUER signal, attendez 5 secondes, s'il fonctionne toujours, il y a un problème.

Cela signifie que vous pouvez configurer le Tomcat pour qu'il s'exécute en tant que démon et utiliser une commande comme celle-ci, ou écrire un script pour effectuer ce type d'action pour arrêter Tomcat, ou simplement utiliser Ubuntu et obtenir le Tomcat depuis le gestionnaire de packages.

6
Utku Özdemir

Dans mon cas, j'avais un EntityManager JPA voyou qui n'était pas correctement fermé après utilisation. Correction de cela, et maintenant je peux à nouveau nettoyer et construire sans tuer le fichu Java processus à chaque fois :)

1
JohannSig

J'ai aussi eu le même problème. Il y avait un ThrottledThreadPoolExecutor dans mon application qui n'obtenait pas d'arrêt. Lorsque je l'éteignais correctement, Tomcat s'arrêtait proprement. Afin de comprendre le problème, j'ai dû supprimer toutes les applications de mon répertoire Tomcat webapps puis les ajouter une par une et voir laquelle était à l'origine du problème

0
Denorm

Si vous utilisez un planificateur ou une autre entité dans votre application Web, vous devez l'arrêter. En règle générale, vous devez utiliser un ServletContextListener pour fournir le hook pour effectuer votre appel d'arrêt. Un hook d'arrêt ne fonctionnera pas dans ce cas car la JVM ne s'arrête pas (encore). Croyez-moi, j'ai essayé. Si votre code est dans le code de l'agent ou quelque chose en dehors du conteneur/de la webapp, alors un crochet d'arrêt DEVRAIT fonctionner, bien que ce soit souvent une expérience de tirer les cheveux pour comprendre pourquoi cela ne fonctionne toujours pas. Remarque, je suis chauve.

0
ticktock