开启Write Ahead的Ignite缓存基准测试遇CacheWriterException及连接池超时
针对你遇到的问题——Write-Through模式正常工作,但开启Write Behind(你配置里的writeBehindEnabled=true,也就是异步写后模式,常被误称为Write Ahead)时出现CacheWriterException和连接池超时,结合你的配置和JMH压测场景,我整理了几个可能的原因及对应的排查方向:
1. Hikari连接池参数无法适配Write Behind的异步批量需求
Write-Through是同步单次写入,每次put操作都会立即占用一个DB连接完成写入后释放;而Write Behind是异步批量写入,Ignite会攒够writeBehindBatchSize条数据后,批量向DB发起写入请求。如果Hikari连接池的默认参数(比如maximumPoolSize、connectionTimeout)太小,在JMH高并发压测下,大量批量写入请求会瞬间耗尽连接池,导致超时。
- 排查建议:
- 调大Hikari的
maximumPoolSize(比如根据压测并发数调整到20~50),同时调长connectionTimeout(比如从默认的3000ms改成10000ms); - 调整Ignite的
writeBehindThreadPoolSize(默认是4),增加异步写入的线程数,避免线程排队导致连接占用时间过长; - 检查Hikari的
idleTimeout和maxLifetime,确保空闲连接不会被过早回收,同时避免连接泄漏。
- 调大Hikari的
2. Write Behind批量配置与数据库性能不匹配
你设置了writeBehindBatchSize=50,意味着Ignite要攒够50条数据才会触发一次批量写入。如果数据库的批量插入性能不足(比如表上有过多索引、DB服务器资源紧张),或者网络延迟较高,单次批量写入会占用连接较长时间,进而导致连接池被占满。
- 排查建议:
- 尝试减小
writeBehindBatchSize(比如改成20),或者调整writeBehindFlushFrequency(默认1000ms),让批量写入更频繁,避免连接长时间被占用; - 检查数据库的性能:比如查看DB的慢查询日志,确认批量插入是否耗时过长;临时关闭非必要的索引,测试写入性能是否提升。
- 尝试减小
3. Ignite异步线程与Spring数据源的上下文兼容性问题
你通过dataSourceBean("dataSource")引用Spring托管的Hikari数据源,而Ignite的Write Behind线程是独立于Spring上下文的线程池,可能存在异步线程无法正确获取数据源代理的情况(虽然Write-Through正常,但同步模式下线程是Spring上下文的,而异步模式是Ignite线程)。
- 排查建议:
- 尝试直接注入数据源实例,而不是通过bean名称;或者将
CacheJdbcPojoStoreFactory交给Spring托管(比如用@Bean声明),确保Ignite能正确获取到Spring管理的数据源; - 检查Hikari的配置是否开启了
registerMbeans,确保异步线程能正常访问数据源的监控和管理Bean。
- 尝试直接注入数据源实例,而不是通过bean名称;或者将
4. 事务配置导致的超时
你的缓存设置了AtomicityMode.TRANSACTIONAL,Write Behind模式下,Ignite可能会为批量写入开启数据库事务。如果数据库的事务超时时间过短,或者批量写入的数据量过大,会导致事务超时,进而触发连接池超时。
- 排查建议:
- 检查数据库的事务超时设置(比如MySQL的
innodb_lock_wait_timeout、PostgreSQL的statement_timeout),适当调大超时时间; - 如果业务允许,可以尝试将
AtomicityMode改为ATOMIC,避免事务带来的额外开销(但注意这会失去事务一致性保障)。
- 检查数据库的事务超时设置(比如MySQL的
5. JMH压测并发量超出系统承载能力
JMH默认的并发线程数可能很高,会快速向Ignite缓存发起大量put请求,导致Write Behind的任务队列堆积,大量批量写入请求同时争抢DB连接,直接耗尽连接池。
- 排查建议:
- 在JMH测试中通过
@Threads注解设置合理的并发数,逐步增加压力,观察系统表现; - 调大Ignite的
writeBehindQueueSize(默认102400),避免任务队列溢出导致的异常。
- 在JMH测试中通过
内容的提问来源于stack exchange,提问作者Prasanth Ravi

