Perfino Java进程重启后高IOWait及APPARENT DEADLOCK问题求助
Perfino重启后高IOWait与长时间恢复问题排查方案
问题核心现象
每日重启Perfino Java进程后,进程占用24-30%的IOWait资源,需等待30-40分钟才能恢复正常;启动日志显示c3p0连接池出现疑似死锁,所有辅助线程卡在H2数据库的连接有效性测试环节。
日志关键信息分析
2022-09-05 09:09:53,390 INFO [main] com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, ... idleConnectionTestPeriod -> 210, initialPoolSize -> 5, jdbcUrl -> jdbc:h2:file:/var/opt/perfino/db/perfino;LOCK_TIMEOUT=30000;DB_CLOSE_ON_EXIT=FALSE;MAX_COMPACT_TIME=5000, ... numHelperThreads -> 3, preferredTestQuery -> null, ... testConnectionOnCheckin -> false, testConnectionOnCheckout -> false ] 2022-09-05 09:13:43,385 WARN [C3P0PooledConnectionPoolManager[...]AdminTaskTimer] com.mchange.v2.async.ThreadPoolAsynchronousRunner: ... APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks! ... Pool thread stack traces: Thread[C3P0PooledConnectionPoolManager[...]HelperThread-#1,5,main] org.h2.command.Command.executeQuery(Command.java:191) org.h2.jdbc.JdbcConnection.getTransactionIsolation(JdbcConnection.java:784) org.h2.jdbc.JdbcConnection.isValid(JdbcConnection.java:1654) com.mchange.v2.c3p0.impl.DefaultConnectionTester$2.activeCheckConnectionNoQuery(DefaultConnectionTester.java:136)
从日志可定位两个核心问题:
- c3p0连接池配置缺陷:
idleConnectionTestPeriod=210开启了定时空闲连接测试,但preferredTestQuery=null,导致使用默认的Connection.isValid()方法验证连接。 - H2数据库IO瓶颈:H2的
isValid()方法会调用getTransactionIsolation(),该操作在数据库重启后需执行日志恢复、文件压缩等大量磁盘IO,导致操作异常缓慢,直接占满c3p0的3个numHelperThreads,触发疑似死锁,阻塞整个应用的数据库操作,同时拉高IOWait。
具体解决步骤
1. 调整c3p0连接池测试策略
- 替换默认连接验证方式:设置
preferredTestQuery为轻量SQL语句,避免调用低效的isValid(),例如添加配置:preferredTestQuery=SELECT 1 - 调整空闲连接测试时机:关闭定时测试
idleConnectionTestPeriod=0,改为在连接归还时测试testConnectionOnCheckin=true,减少不必要的后台IO操作。 - 临时扩容辅助线程:调大
numHelperThreads(如设置为5),避免测试任务瞬间占满线程池,这是临时缓解方案,核心仍需优化验证逻辑。
2. 优化H2数据库配置与维护
- 预压缩H2数据库:重启Perfino前,手动连接H2数据库执行压缩命令,降低启动时的IO负载:
CHECKPOINT; COMPACT; - 调整H2 JDBC参数:
- 增大
MAX_COMPACT_TIME(如改为10000),避免启动时频繁触发压缩; - 添加
AUTO_RECONNECT=TRUE确保连接异常时自动恢复; - 若数据库文件过大,考虑迁移至SSD等高效存储介质。
- 增大
- 升级H2版本:旧版本H2的
getTransactionIsolation()存在性能缺陷,升级到最新稳定版可解决部分IO阻塞问题。
3. 优化Perfino重启流程
- 延迟连接池初始化:修改Perfino启动脚本,先通过执行简单SQL判断H2数据库是否完成启动恢复,再初始化c3p0连接池。
- 减小初始连接数:降低
initialPoolSize(如改为2),避免启动时同时创建多个连接触发集中IO。
内容的提问来源于stack exchange,提问作者Juanjo
相关产品推荐
相关产品推荐

