Я работаю над приложением, основанным на 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.
Как я могу знать, что я сделал неправильно?
Очевидно, что эти запросы блокируются, но не освобождаются. Возможно, вы получаете какое-то исключение или что-то, чего вы не видите, потому что запрос помечен как ROLLBACK
, и по какой-то причине поток висит в ожидании завершения запроса или что-то в этом роде. Не видя кода, его трудно сказать точно.
Что вы можете сделать, так это дождаться, когда это произойдет снова, а затем получите полный дамп потока. Это должно дать вам полную информацию о том, где висит нить, поэтому вы можете видеть, что ждет 20 подключений.
Вы можете использовать jstack для этого, который поставляется вместе с JDK.
Вы также можете включить JMX на Tomcat и подключиться к нему с помощью jconsole или jvisualvm, чтобы в реальном времени видеть, что делают потоки.
com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable
. Использование jconsole или jvisualvm просто даст точно такой же след.
try ... finally
, и вы закрываете соединение в finally
? Без примера кода его сложно сказать.
Похоже, ваше приложение исчерпало доступные объединенные соединения. Транзакция отмечена как откат только в случае возникновения исключения. Если вы не можете увидеть какое-либо исключение, это может быть связано с тем, что вы неправильно обрабатываете их, например, регистрируете любое исключение с порогом ERROR.
Вам также нужно проверить журнал db, возможно, вы обнаружите, что приводит к откату всех этих транзакций.