Как я могу узнать, почему мое приложение, использующее PostgreSQL 9, hibernate 4.3.5 и c3p0, зависает?

1

Я работаю над приложением, основанным на PostgreSQL 9, hibernate 4.3.5.Final, c3p0, Tomcat 7 и JDK 7.

Вот конфигурация c3p0:

hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50

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

Я убил -3 в процессе tomcat 7 (развернуто одно приложение), чтобы увидеть, где все потоки заблокированы. Здесь часть результата:

"ajp-bio-8127-exec-274" daemon prio=10 tid=0x0000000001365000 nid=0x257b in Object.wait() [0x0000000045242000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1414)
    at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:606)
    - locked <0x000000078567cb70> (a com.mchange.v2.resourcepool.BasicResourcePool)
    at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:526)
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectio

Это то же самое для всех процессов запросов HTTP. Таким образом, все запросы ждут неопределенно для доступного соединения в пуле.

Мы посмотрели postgres, чтобы увидеть, что было открыто 20 соединений (20 - максимальный размер пула):

foobar=# select datname, usename, client_port, query from  pg_stat_activity where usename='foobar';
 datname | usename | client_port |  query
---------+---------+-------------+----------
 foobar  | foobar  |       52992 | ROLLBACK
 foobar  | foobar  |       52993 | ROLLBACK
 foobar  | foobar  |       52991 | ROLLBACK
 foobar  | foobar  |       52994 | ROLLBACK
 foobar  | foobar  |       52995 | ROLLBACK
 foobar  | foobar  |       36398 | ROLLBACK
 foobar  | foobar  |       36399 | ROLLBACK
 foobar  | foobar  |       36400 | ROLLBACK
 foobar  | foobar  |       51766 | ROLLBACK
 foobar  | foobar  |       56689 | ROLLBACK
 foobar  | foobar  |       56690 | ROLLBACK
 foobar  | foobar  |       39582 | ROLLBACK
 foobar  | foobar  |       39581 | ROLLBACK
 foobar  | foobar  |       39583 | ROLLBACK
 foobar  | foobar  |       39590 | ROLLBACK
 foobar  | foobar  |       39592 | ROLLBACK
 foobar  | foobar  |       39591 | ROLLBACK
 foobar  | foobar  |       41799 | ROLLBACK
 foobar  | foobar  |       36105 | ROLLBACK
 foobar  | foobar  |       36103 | ROLLBACK
(20 rows)

Итак, мы настроили журналы пулов на DEBUG, и мы можем видеть утверждения, подобные тезисам:

2014/07/09 05:24:40 DEBUG (BasicResourcePool.java:1747) trace trace com.mchange.v2.resourcepool.BasicResourcePool@12c39c9e [managed: 19, unused: 4, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@4fc04747)

Они показывают, что номер управляемой связи растет медленно до тех пор, пока не управляется: 20 и usused: 0 это конечное состояние остается стабильным и приложение заморожено, потому что все потоки ожидают, что соединение будет доступно из пула.

Это веб-приложение, и мы используем сессию в шаблоне запроса, чтобы соединение закрывалось должным образом после обработки каждого запроса (в заявлении finally). В журналах приложений нет такой вещи, как ERROR или WARN.

Как я могу знать, что я сделал неправильно?

  • 1
    Не могли бы вы указать код, который вы используете для открытия и закрытия соединения? (не только отдельные строки, включите часть контекста, в котором вы их делаете)
  • 2
    Это GPL-лицензированное программное обеспечение, вы можете проверить исходный код , заявление try..finally в этом классе
Показать ещё 6 комментариев
Теги:
hibernate
c3p0

2 ответа

1

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

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

Вы можете использовать jstack для этого, который поставляется вместе с JDK.

Вы также можете включить JMX на Tomcat и подключиться к нему с помощью jconsole или jvisualvm, чтобы в реальном времени видеть, что делают потоки.

  • 2
    Как я уже сказал в вопросе, я уже знаю, где все темы висят. Все они заблокированы на com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable . Использование jconsole или jvisualvm просто даст точно такой же след.
  • 1
    Ну, у вас должно быть 2 вида висящих нитей. До сих пор вы показали, какие нити зависают после возникновения проблемы. Те законно висят, потому что они ждут, чтобы соединение было доступно. Другие типы потоков (у вас должно быть 20) должны висеть где-то еще ... если только у вас нет места, где вы не возвращаете соединение. Вы уверены, что все места, где вы получаете соединение, окружены блоком try ... finally , и вы закрываете соединение в finally ? Без примера кода его сложно сказать.
0

Похоже, ваше приложение исчерпало доступные объединенные соединения. Транзакция отмечена как откат только в случае возникновения исключения. Если вы не можете увидеть какое-либо исключение, это может быть связано с тем, что вы неправильно обрабатываете их, например, регистрируете любое исключение с порогом ERROR.

Вам также нужно проверить журнал db, возможно, вы обнаружите, что приводит к откату всех этих транзакций.

  • 2
    Я правильно обрабатываю исключения. Мой стиль кода подразумевает строгое правило пустого предложения catch, поэтому я думаю, что исключений не возникало никогда. Вот почему проблема такая ... раздражающая. К сожалению, у меня нет доступа к производственной платформе. Надеюсь, что администратор сможет дать мне журналы PG :-(

Ещё вопросы

Сообщество Overcoder
Наверх
Меню