Tomcat не останавливается. Как я могу отладить это? - PullRequest
32 голосов
/ 02 апреля 2012

У меня Tomcat 7 работает в Linux, я запускаю через $CATALINA_HOME/bin/startup.sh и выключаю через $CATALINA_HOME/bin/shutdown.sh
от /etc/init.d

Все в порядке, кроме 1 проблемы. Иногда кот не останавливается.
Несмотря на то, что я остановил это и вижу в журналах catalina.out, что происходит сбой, если я делаю ps -ef, я все равно вижу, что процесс запущен.

В чем может быть проблема? Как я могу отладить это? Мне кажется, что это связано с темами.

Итак, подозрительные части следующие:
1) Я использую LogManager Log4j, чтобы определить, была ли изменена конфигурация log4j, но я делаю Log4jManager.shutdown на contextDestroyed ServletContextListener
2) Я использую H2 базу данных и вижу при выключении:

SEVERE: веб-приложение [/ MyApplication], похоже, запустило
поток с именем [H2 Log Writer MYAPPLICATION], но не смог остановить его.
Это очень вероятно, чтобы создать утечку памяти

SEVERE: веб-приложение [/ MyApplication], похоже, запустило
поток с именем [H2 File Lock Watchdog
/opt/myOrg/tomcat/webapps/MyApplication/db/myDatabase.lock.db], но имеет
не смог остановить это. Это очень вероятно, чтобы создать утечку памяти. 2 апреля
2012 9:08:08 org.apache.catalina.loader.WebappClassLoader
clearReferencesThreads SEVERE: веб-приложение [/ MyApplication]
Похоже, что он начал поток с именем [FileWatchdog], но не удалось
чтобы остановить это. Это очень вероятно, чтобы создать утечку памяти.

Любая помощь, пожалуйста? Как я могу обнаружить проблему здесь?

UPDATE:
Я сделал kill -3, как предложено @daveb, и в catalina.out я вижу:

JVMDUMP006I Обрабатывается событие дампа "user", detail "" - пожалуйста, подождите. JVMDUMP032I JVM запросил дамп Java с помощью '/etc/init.d/javacore.20120402.093922.2568.0001.txt' в ответ на событие JVMDUMP010I Дамп Java, записанный в /etc/init.d/javacore.20120402.093922.2568.0001.txt JVMDUMP013I Обработано событие дампа "пользователь", деталь "".

В /etc/init.d есть javacore, но я не знаю, как его обработать. То есть какие части я должен исследовать

Ответы [ 7 ]

19 голосов
/ 02 апреля 2012

Узнайте, какие потоки все еще работают (или заблокированы, ожидая запуска), используя jstack или отправив сигнал процессу:

kill -3 pid

Когда вы это знаете, вы можете сделать все, что бы они ни начали, подключить их к уведомлению о выключении, чтобы остановить потоки. Или сделай эти темы темными.

См. Этот вопрос о закрытии кота для более подробной информации.

Если вы не знаете, где были созданы ваши потоки, подумайте о том, чтобы добавить к ним имена - исполнители могут использовать фабрики потоков, и вы можете использовать эти фабрики, чтобы установить статус потока, а также присвоить ему имя - так что ваш трассировка стека будет более четкой.

7 голосов
/ 08 сентября 2014

Проверьте, не активен ли в вашем веб-приложении планировщик, например, Quartz.

Если вы не остановите это, поток веб-приложений никогда не прекратится, пока вы его не убьете

6 голосов
/ 17 февраля 2014

У меня была точно такая же проблема. Иногда команда ./shutdown.sh не останавливает процесс tomcat, и ее java процесс остается в запущенных процессах.

Я решил эту проблему, используя версию Tomcat в репозиториях программного обеспечения Ubuntu:

sudo apt-get install tomcat7

После установки из диспетчера пакетов и настройки некоторых параметров у меня не возникло проблем при остановке / запуске Tomcat. Я использовал эту команду для остановки, и она никогда не заканчивалась:

service tomcat7 stop

, что почти совпадает с

/etc/init.d/tomcat7 stop

С помощью этой команды запускается блок кода из сценария инициализации, в частности коды из файла /etc/init.d/tomcat7. Поэтому я посмотрел в него, чтобы увидеть, что он делает, чтобы всегда успешно завершать процесс tomcat Вот блок кода, который запускается при использовании команды service tomcat7 stop:

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
        ;;

Важная часть такова:

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

Это означает «повторная остановка до тех пор, пока процесс не будет остановлен. Вот документация команды --retry из start-stop-daemon manual:

   -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.
          ...

Итак, --retry=TERM/20/KILL/5 означает «Отправить TERM сигнал процессу, подождать 20 секунд, если он все еще работает, отправить сигнал KILL , подождать 5 секунд, если он все еще работает» есть проблема.

Это означает, что вы можете настроить tomcat для запуска в качестве демона и использовать команду, подобную этой, или написать скрипт для выполнения такого рода действия, чтобы остановить tomcat, или просто использовать Ubuntu и получить tomcat из диспетчера пакетов.

4 голосов
/ 02 апреля 2012

Если веб-приложение остановлено, все подключения к базе данных также должны быть закрыты. Если у вас нет списка подключений, выполните оператор SQL «shutdown» (это работает только для баз данных H2 и HSQLDB).

Если у вас есть зарегистрированный сервлет, вы можете сделать это методом Servlet.destroy().

Если вы зарегистрировали ServletContextListener, вы можете выполнить оператор shutdown в методе ServletContextListener.contextDestroyed(ServletContextEvent servletContextEvent). Это то, что делает org.h2.server.web.DbStarter ServletContextListener (тот, который включен в базу данных H2).

1 голос
/ 30 декабря 2014

В моем случае у меня был один мошеннический JPA EntityManager, который после использования не закрывался должным образом. Исправлено, и теперь я могу снова чистить и строить, не убивая проклятый процесс Java каждый раз:)

0 голосов
/ 03 августа 2016

Если вы используете Планировщик или какой-либо другой объект в своем веб-приложении, вам необходимо отключить его. Как правило, вы должны использовать ServletContextListener для подключения к вызову завершения работы. В этом случае хук отключения не будет работать, потому что JVM не выключается (пока). Поверьте мне, я пытался. Если ваш код находится в коде агента или что-то вне контейнера / веб-приложения, то СЛЕДУЕТ работать ловушке отключения, хотя часто бывает сложно потрудиться выяснить, почему она ПО-прежнему не работает. Обратите внимание, я лысый.

0 голосов
/ 09 декабря 2015

У меня тоже была такая же проблема. В моем приложении был ThrottledThreadPoolExecutor, который не отключался. Когда я его правильно выключу, кот полностью остановится. Чтобы выяснить проблему, мне пришлось удалить все приложения из моего каталога tomcat webapps, а затем добавить их одно за другим и посмотреть, какое из них вызывало проблему

...