Liferay+Tomcat(Atomikos)线程阻塞致应用卡顿问题排查求助
问题描述
环境配置
基于Liferay + Tomcat + PostgreSQL的应用,Tomcat配置Atomikos作为事务管理器,数据源配置如下:
<Resource name="jdbc/liferay" auth="Container" type="com.atomikos.jdbc.AtomikosDataSourceBean" factory="com.atomikos.tomcat.EnhancedTomcatAtomikosBeanFactory" uniqueResourceName="jdbc/liferay" maxPoolSize="500" minPoolSize="10" borrowConnectionTimeout="30" maxIdleTime="60" reapTimeout="0" maintenanceInterval="60" testQuery="SELECT 1" xaDataSourceClassName="org.postgresql.xa.PGXADataSource" xaProperties.serverName="${host}" xaProperties.portNumber="${port}" xaProperties.user="${user}" xaProperties.databaseName="${database}" xaProperties.password="${password}" /> <Resource name="jdbc/service" auth="Container" type="com.atomikos.jdbc.AtomikosDataSourceBean" factory="com.atomikos.tomcat.EnhancedTomcatAtomikosBeanFactory" uniqueResourceName="jdbc/service" maxPoolSize="100" minPoolSize="10" borrowConnectionTimeout="30" maxIdleTime="60" reapTimeout="0" maintenanceInterval="60" testQuery="SELECT 1" xaDataSourceClassName="org.postgresql.xa.PGXADataSource" xaProperties.serverName="${host}" xaProperties.portNumber="${port}" xaProperties.databaseName="service" xaProperties.user="${user}" xaProperties.password="${password}" />
故障现象
应用随机出现卡顿(每小时数次),卡顿期间无法处理任何请求,线程数激增。
线程Dump分析
大部分线程处于BLOCKED状态,等待获取Atomikos连接池的锁:
"http-apr-443-exec-163" - Thread t@17821 java.lang.Thread.State: BLOCKED at com.atomikos.datasource.pool.ConnectionPool.borrowConnection(ConnectionPool.java:127) - waiting to lock <8e7fbf9> (a com.atomikos.datasource.pool.ConnectionPool) owned by "http-apr-443-exec-10" t@223
而持有锁的线程处于RUNNABLE状态,但卡在PostgreSQL的SSL连接建立阶段:
"http-apr-443-exec-10" - Thread t@223 java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at org.postgresql.core.VisibleBufferedInputStream.readMore(VisibleBufferedInputStream.java:161) at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:128) at org.postgresql.core.VisibleBufferedInputStream.ensureBytes(VisibleBufferedInputStream.java:113) at org.postgresql.core.VisibleBufferedInputStream.read(VisibleBufferedInputStream.java:73) at org.postgresql.core.PGStream.receiveChar(PGStream.java:443) at org.postgresql.core.v3.ConnectionFactoryImpl.enableSSL(ConnectionFactoryImpl.java:505) at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:149) at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:213) at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:51) at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:223) at org.postgresql.Driver.makeConnection(Driver.java:465) at org.postgresql.Driver.connect(Driver.java:264)
疑问
这可能是什么原因?是死锁还是Atomikos配置错误?
问题分析与解决方案
这不是死锁,而是Atomikos连接池锁被长时间持有导致的全局阻塞,具体原因和解决思路如下:
核心原因
- Atomikos连接池锁的设计缺陷:旧版本Atomikos的
ConnectionPool.borrowConnection()方法中,整个连接获取(包括新建连接)流程都持有全局锁。当某个线程需要新建PostgreSQL连接时,若遇到SSL握手超时、网络延迟等情况,会长时间占用锁,导致所有其他请求线程阻塞在锁等待步骤上。 - PostgreSQL SSL连接延迟:持有锁的线程卡在
enableSSL阶段,说明SSL握手过程存在不可控延迟(如网络波动、PostgreSQL服务器SSL处理缓慢、证书验证耗时等),且该延迟发生在锁的持有周期内,直接引发全局阻塞。 - 连接池配置不合理:
reapTimeout=0:关闭了空闲连接回收机制,可能导致连接池无法及时清理闲置连接,增加新建连接的概率;borrowConnectionTimeout=30:超时时间过长,线程会在锁上等待更久,加剧卡顿范围。
解决方案
- 升级Atomikos版本:较新版本已优化连接池锁的粒度,将新建连接的逻辑移出锁范围,避免在锁内执行耗时的网络操作。
- 解决PostgreSQL SSL连接问题:
- 排查网络链路稳定性,确认是否存在丢包、延迟波动;
- 调整PostgreSQL SSL配置,比如使用更高效的加密算法,测试环境可临时禁用SSL(添加
xaProperties.ssl=false到数据源配置); - 检查证书有效性及验证流程,优化证书加载速度。
- 调整连接池参数:
- 设置合理的
reapTimeout(如60),让空闲连接被及时回收,减少新建连接频率; - 降低
borrowConnectionTimeout(如10),避免线程长时间阻塞; - 确保
minPoolSize足够覆盖日常请求量,减少高峰时段新建连接的需求; - 匹配Tomcat线程池配置,避免线程数过多导致系统资源耗尽。
- 设置合理的
- 监控连接池状态:添加Atomikos连接池监控,跟踪连接的获取、新建、回收情况,排查是否存在连接泄漏或新建连接过于频繁的问题。
内容的提问来源于stack exchange,提问作者Udepentctrsp
相关产品推荐
相关产品推荐

