【问题标题】:APPARENT DEADLOCK c3p0 0.9.5.1 spring表观死锁 c3p0 0.9.5.1 弹簧
【发布时间】:2015-06-20 10:22:45
【问题描述】:

在使用 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 有帮助吗?

【问题讨论】:

  • 也许改变池的实现会有所帮助。您需要找出死锁的原因,因为数据库也可能导致这种情况。如果您有包含表锁定的并发写入,则原因可能在应用程序本身内部。如果存在锁,您还需要检查数据库端 - 然后弄清楚它是如何产生的。

标签: java mysql connection-pooling spring-jdbc c3p0


【解决方案1】:

您遇到的问题是语句缓存。切换到不缓存语句的其他池可能会有所帮助。但是通过将 maxStatements 设置为 0 来关闭 c3p0 中的语句缓存将有助于以完全相同的方式。如果不缓存语句,则不必担心语句缓存中的死锁。但也许您会享受语句缓存带来的性能提升。

幸运的是,如果您愿意,您可以保留语句缓存的性能优势,而无需迁移到其他池。

问题是某些 DBMS/JDBC 驱动程序无法处理在其父连接正在使用的同时关闭的语句。形式上,这应该没问题,但实际上它不适用于某些 JDBC 驱动程序。当 Statement 缓存尝试使其父 Connection 恰好正在使用的 Statement 过期时,对 close() 的调用将死锁,最终使线程池饱和并冻结。

c3p0 包含针对这些脆弱驱动程序的解决方法。

将 c3p0 配置参数 statementCacheNumDeferredCloseThreads 设置为 1,c3p0 将神经质地跟踪即将到期的 Statement 的父级是否正在使用,并将 close() 调用推迟到没有使用。希望此设置可以解决您的问题。

我猜你的 Spring XML 中的配置应该是这样的

p:statementCacheNumDeferredCloseThreads="1"

我希望这会有所帮助!

【讨论】:

  • 感谢史蒂夫的帮助。我会尝试并发布结果。
  • 它解决了这个问题。感谢您的帮助,我检查了文档,它确实谈到了这个设置。理想情况下,它应该设置为默认值。这有什么坏处吗?
  • 每个数据源有一个额外的专用线程的开销,并且在管理异步语句关闭操作时有点额外的复杂性。这些确实是唯一的缺点。
  • @EmreTürkiş 我很高兴它有帮助!
  • 如果你的池只有一个线程,一个缓慢的任务可能会引发死锁检测。请尝试将hibernate.c3p0.numHelperThreads 设置为 8-to-10-ish,因为它看起来将是您的池的规模。 (c3p0 的默认线程池大小为 3;我不知道您为什么会以单个线程结束。)
猜你喜欢
  • 1970-01-01
  • 2023-03-27
  • 2019-03-15
  • 1970-01-01
  • 2017-06-13
  • 1970-01-01
  • 2016-06-02
  • 1970-01-01
  • 2019-03-19
相关资源
最近更新 更多