ЯВНАЯ БЛОКИРОВКА c3p0 0.9.5.1 spring

Мы столкнулись с ЯВНОЙ ТУПИЧНОЙ БЛОКИРОВКОЙ при использовании c3p0 0.9.5.1 (последняя версия c3p0). Ниже приведена конфигурация пула соединений, которую мы используем.

      p:driverClass="${app.jdbc.driverClassReplica}"
      p:jdbcUrl="jdbc:mysql://database,database/dbname"
      p:acquireIncrement="5"
      p:idleConnectionTestPeriod="300"
      p:maxPoolSize="100"
      p:maxStatements="2000"
      p:minPoolSize="10" 
      p:maxIdleTime="1800"
      p:maxConnectionAge="3600"
      p:maxIdleTimeExcessConnections="20"
      p:numHelperThreads="15"
      p:preferredTestQuery="SELECT 1"/>

и следующие журналы

ThreadPoolAsynchronousRunner:743---- com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@70f6e5f5 -- A
PPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks! #]
2015-06-20 11:36:15 WARN  ThreadPoolAsynchronousRunner:759---- com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@70f6e5f5 -- A
PPARENT DEADLOCK!!! Complete Status: 
        Managed Threads: 15
        Active Threads: 15
        Active Tasks: 

Каждая активная задача выглядит как

com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@4ec69595
                        on thread: C3P0PooledConnectionPoolManager[identityToken->z8kflt9a33udv812q4fqf|60dffe1d]-HelperThread-#6

Незавершенные задачи:

com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@2b131ea8
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@7441bdaf
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@80c67ca
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@667202e6
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@471c7e95
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@1fba8cac
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@1069807a
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@7e71d200
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@62923eda
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@6f5c8cc4
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@251dd0fa
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@4882e01f
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@848386a
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@3d6fbb65
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@72780365
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@25271699
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@293ca9dd
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@4db40151
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@64c294b1
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@22b02425
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@5a150aed
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@1b807bcf
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@10406124
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@72a98ad1
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@58d8da26
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@2a013697
com.mchange.v2.c3p0.stmt.GooGooStatementCache$1StmtAcquireTask@35a7090c
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@69430e58
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@3162e965
com.mchange.v2.resourcepool.BasicResourcePool$1RefurbishCheckinResourceTask@54c8ff37
com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask@57eb9f5d

Трассировки стека потоков пула: все 15 потоков выглядят следующим образом

Thread[C3P0PooledConnectionPoolManager[identityToken->z8kflt9a33udv812q4fqf|60dffe1d]-HelperThread-#6,5,main]
                com.mysql.jdbc.StatementImpl.close(StatementImpl.java:575)
                com.mchange.v1.db.sql.StatementUtils.attemptClose(StatementUtils.java:53)
                      com.mchange.v2.c3p0.stmt.GooGooStatementCache$StatementDestructionManager$1UncheckedStatementCloseTask.run(GooGooStatementCache.java:938)

Всякий раз, когда это происходит, db перестает отвечать на запросы на некоторое время, а количество подключений увеличивается до db. Это проблема с c3p0 ?? Поможет ли переход на другой пул jdbc, такой как hikaricp или boncecp?


person user3679447    schedule 20.06.2015    source источник
comment
возможно, изменение реализации пула поможет. вам нужно выяснить причину тупика, потому что база данных также может вызвать это. Если у вас есть одновременные записи, которые включают блокировку таблицы, причина может быть внутри самого приложения. Также нужно проверить на стороне базы данных наличие блокировок — а потом разобраться, как до этого дошло.   -  person wemu    schedule 20.06.2015


Ответы (1)


У вас проблема с кэшем операторов. Может помочь переключение на другие пулы, которые не кэшируют операторы. Но отключение кэширования операторов в c3p0 путем установки maxStatements на 0 помогло бы точно так же. Если вы не кэшируете операторы, вам не нужно беспокоиться о взаимоблокировках в кэше операторов. Но, возможно, вам понравится повышение производительности за счет кэширования операторов.

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

Проблема в том, что некоторые драйверы СУБД/JDBC не могут справиться с закрытием оператора во время использования его родительского соединения. Формально это должно быть хорошо, но на практике это не так для некоторых драйверов JDBC. Когда кеш операторов пытается истечь срок действия оператора, родительское соединение которого используется, вызов close() блокируется, в конечном итоге насыщая и замораживая пул потоков.

c3p0 включает обходной путь для этих хрупких драйверов.

Установите для параметра конфигурации c3p0 statementCacheNumDeferredCloseThreads значение 1, и c3p0 будет невротически отслеживать, является ли родитель используется оператор с истекающим сроком действия, и отложите вызов close() до тех пор, пока он не исчезнет. Надеемся, что этот параметр решит вашу проблему.

Я предполагаю, что в вашем Spring XML конфигурация будет выглядеть так

p:statementCacheNumDeferredCloseThreads="1"

Надеюсь, это поможет!

person Steve Waldman    schedule 20.06.2015
comment
Спасибо Стиву за помощь. Я попробую и отпишусь о результатах. - person user3679447; 20.06.2015
comment
Это решило проблему. Спасибо за помощь, я проверил документацию, и в ней говорится об этой настройке. В идеале он должен быть установлен по умолчанию. Есть ли в этом минусы? - person user3679447; 25.06.2015
comment
Есть накладные расходы на дополнительный выделенный поток для каждого источника данных и немного дополнительная сложность в управлении асинхронными операциями закрытия операторов. Это действительно единственные минусы. - person Steve Waldman; 25.06.2015
comment
@EmreTürkiş, я рад, что это помогло! - person Steve Waldman; 17.09.2015
comment
Привет @SteveWaldman, я думал, что наконец нашел решение здесь, но у меня такая же ошибка даже с операторомCacheNumDeferredCloseThreads=1. Я использую Mysql 5.5 и последнюю версию mysql-connector/j 5.1.42. Следует отметить, что ошибка никогда не возникает со старым коннектором 5.1.11. - person user and; 05.06.2017
comment
та же самая ошибка, означающая КАЖУЩИЙСЯ ТУБЛОК? у вас тоже есть такие же активные задачи? - person Steve Waldman; 06.06.2017
comment
Да, это был ЯВНЫЙ ТУПИК. Но странно, что была только одна задача (Active Threads: 1, Active Task: 1). Я не могу воспроизвести его снова для полной трассировки стека, но это было. Без statementCacheNumDeferredCloseThreads=1 проблема темы возникает очень часто, с ней я ловлю ее только один раз при загрузке на сцене. - person user and; 07.06.2017
comment
Если в вашем пуле только один поток, простая медленная задача может спровоцировать обнаружение взаимоблокировки. Пожалуйста, попробуйте установить hibernate.c3p0.numHelperThreads, возможно, от 8 до 10, учитывая, что это похоже на масштаб вашего пула. (Размер пула потоков по умолчанию для c3p0 равен трем; я не знаю, почему у вас получается один поток.) - person Steve Waldman; 07.06.2017