Подтвердить что ты не робот

Java-приложение в tomcat периодически зависает

Мое Java-приложение под управлением Tomcat (7.0.28) периодически перестает отвечать на запросы. Я надеюсь на некоторые предложения возможных преступников (синхронизация?), А также, возможно, некоторые рекомендуемые инструменты для сбора дополнительной информации о том, что происходит во время сбоя. Некоторые факты, которые я накопил:

  • Когда веб-приложение зависнет, tomcat продолжает подавать потоки запросов в приложение, но приложение не освобождает их. Пул потоков заполняется до максимума (в настоящее время 250), а затем последующие запросы немедленно терпят неудачу. Во время нормальной работы не более 2 или 3 активных потоков.

  • При возникновении проблемы нет ошибок или исключений любого вида, зарегистрированных в любом из журналов tomcat или веб-приложений.

  • Выполнение "Стоп", а затем "Начать" в нашем приложении через веб-приложение управления tomcat немедленно устраняет эту проблему (до сегодняшнего дня).

  • В последнее время частота была два или три раза в день, хотя сегодня было намного хуже, вероятно, 20 раз, и иногда не возвращалось к жизни немедленно.

  • Проблема возникает только в рабочее время

  • Проблема не возникает в нашей промежуточной системе

  • При возникновении проблемы использование процессора и памяти на сервере остается плоским (и довольно низким). Tomcat сообщает о большом количестве свободной памяти.

  • Tomcat продолжает реагировать, когда возникает проблема. Веб-приложение управления работает отлично, и tomcat продолжает отправлять запросы в наше приложение, пока не будут заполнены все потоки в пуле.

  • Наш сервер баз данных остается отзывчивым, когда возникает проблема. Мы используем инфраструктуру Spring для доступа к данным и инъекции.

  • Проблема обычно возникает, когда использование является высоким, но никогда не бывает необычно высокого всплеска в использовании.

  • История проблем: что-то подобное произошло около полутора лет назад. После многих изменений в конфигурации сервера и кода проблема исчезла примерно до месяца назад. В течение последних нескольких недель это происходило гораздо чаще, в среднем 2 или 3 раза в день, иногда несколько раз подряд.

  • Сегодня я определил некоторый код сервера, который, возможно, не был потокобезопасным, и я установил исправление для него, но проблема все еще происходит (хотя и реже). Является ли это той проблемой, которую может вызвать не-потоковый код?

ОБНОВЛЕНИЕ:. С несколькими сообщениями, в которых говорится об исчерпании пула подключений к базе данных, я сделал несколько поисков в этом направлении и нашел этот другой qaru.site/info/247356/..., который объясняет почти все проблемы, которые я испытываю.

По-видимому, значения по умолчанию для соединений maxActive и maxIdle в реализации Apache BasicDataSource равны 8. Кроме того, maxWait установлен на -1, поэтому, когда пул исчерпан и появляется новый запрос на соединение, он будет ждать вечно без регистрации каких-либо исключений. Я все еще жду, когда эта проблема повторится, и выполните jstack dump на JVM, чтобы я мог анализировать эту информацию, но похоже, что это проблема. Единственное, что не объясняет, почему приложение иногда не восстанавливается после этой проблемы. Я полагаю, что запросы просто накапливаются иногда, и как только он позади, он никогда не сможет догнать.

ОБНОВЛЕНИЕ II: Я столкнулся с jstack во время сбоя и обнаружил около 250 (максимальных потоков) следующего содержания:

"http-nio-443-exec-294" daemon prio=10 tid=0x00002aaabd4ed800 nid=0x5a5d in Object.wait() [0x00000000579e2000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:485)
        at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1118)
        - locked <0x0000000743116b30> (a org.apache.commons.pool.impl.GenericObjectPool$Latch)
        at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
        at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
        at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
        at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674)
        at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:718)

Для моего неподготовленного глаза это выглядит довольно убедительно. Похоже, что пул подключений к базе данных попал в кепку. Я сконфигурировал maxWait из трех секунд без изменения maxActive и maxIdle, чтобы убедиться, что мы начинаем видеть исключения, регистрируемые при заполнении пула. Затем я установлю эти значения на что-то подходящее и контролирую.

ОБНОВЛЕНИЕ III: После настройки maxWait я начал видеть их в своих журналах, как и ожидалось:

 org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object
        at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114)
        at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
        at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
        at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)

Я установил maxActive на -1 (бесконечный) и maxIdle на 10. Я буду контролировать некоторое время, но я предполагаю, что это конец проблемы.

4b9b3361

Ответ 1

По опыту, вы можете взглянуть на реализацию пула соединений с базами данных. Возможно, ваша база данных имеет большую емкость, но пул соединений в вашем приложении ограничен небольшим количеством подключений. Я не помню подробностей, но, похоже, я помню, что у меня была аналогичная проблема, и это была одна из причин, по которой я перешел на использование BoneCP, который я нашел быть очень быстрым и надежным при испытаниях нагрузки.

После попытки отладки, предложенной ниже, попробуйте увеличить количество подключений, доступных в пуле, и посмотреть, не влияет ли это на них.

Сегодня я определил код сервера, который, возможно, не был потоковым, и я поставил исправление для этого, но проблема все еще происходит (хотя реже). Является ли это той проблемой, которая может быть вызван не-потоковый код?

Это зависит от того, что вы подразумеваете под потоковой безопасностью. Мне кажется, что ваше приложение вызывает темы deadlock. Возможно, вы захотите запустить свою производственную среду с помощью JVM, настроенной на то, чтобы позволить отладчику подключаться, а затем использовать JVisualVM, JConsole или другой инструмент профилирования (YourKit - отличный IMO), чтобы заглянуть в то, что у вас есть, и что они "ждут".