Updated on 五月 15, 2020
高并发SqlSession close前新开SqlSession导致阻塞问题
最近测试程序的高并发,发现高并发下卡死,百分之百复现。经过一天的调查,最终定位问题所在。
程序结构为:
SqlSession session = DbUtil.getSession(); try{ ... SqlSession session2 = DbUtil.getSession(); try{ ... } finally { session2.close(); } ... } finally { session.close(); }
当高并发访问时,session申请掉了所有的数据库连接,当进入到session2时,无法获取到新的数据库连接,阻塞,导致session无法执行到close,没有新的连接可用,整个程序无法获取新的数据库连接。
可以尝试减少服务的最大线程数,增加数据库的最大连接数,使得数据库连接数大于服务线程数。但是这样治标不治本。
能想到两个办法:
1、将这种session内申请session的都修改要么移到session外,要么使用前面的session。也就是从代码逻辑上规避。
2、设置Druid的MaxWait,例如设置为2000(毫秒)
参考:
Druid数据库连接池配置(案例及排查指南)
https://tech.youzan.com/shu-ju-ku-lian-jie-chi-pei-zhi/
更新:
设置Druid的removeAbandoned,removeAbandonedTimeout将超过20秒的连接停止掉。
设置logAbandoned打印出来abandoned的连接。
https://www.cnblogs.com/spec-dog/p/6226212.html
总结:
1、修改代码,将所有事务内嵌套事务改为单线事务
2、优化代码,对于查数据库能缓存的做缓存处理;优化sql
3、尝试不同的Druid连接池配置及ICE最大线程数,寻找较优组合
4、配置Druid的removeAbandoned,释放长时间未完成的连接
5、更新Druid、pg库
6、尝试将Druid更换为HiKariCP,未见改善,改回Druid