问题场景:测试seata分布式事务回滚
问题现象:shop模块调用user模块创建新的user,并在shop模块中抛出异常,触发全局回滚。shop模块触发回滚成功,但是user模块读取超时。而且后续向user模块发送请求均被阻塞。
问题分析:通过查看模块的日志,seata全局事务出发回滚正常,也未发现任何异常日志,同时seata打印也正常,怀疑是user的主线程被阻塞导致user模块的异常。
通过jstat或者VisualVM打印user模块堆栈信息,发现一个线程因为等待获取数据库连接而处于waiting状态,怀疑是等待数据库连接而被阻塞。
"http-nio-8085-exec-1" #118 daemon prio=5 os_prio=31 tid=0x00007fa8a731a800 nid=0x7703 waiting on condition [0x000070000cba4000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007b13ad5c8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at com.alibaba.druid.pool.DruidDataSource.takeLast(DruidDataSource.java:2094)
at com.alibaba.druid.pool.DruidDataSource.getConnectionInternal(DruidDataSource.java:1620)
at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1395)
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1375)
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:1365)
at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:109)
问题解决:查看druid的数据库连接配置,发现最大连接数被设置成了1,原本的创建用户时占用了一个数据库连接,猜测是seata在执行回滚时需要另起一路连接。而当前user模块数据库最大连接数为1,原本的创建用户操作等待全局执行的结果而尚未提交,导致唯一的数据库连接未释放,而回滚时又在等待获取连接,因而导致了主线程的阻塞。