mianshiba / dailytech

日常使用核心技术
0 stars 0 forks source link

一次spring boot应用无法处理请求的问题排查实践 #7

Open mianshiba opened 3 years ago

mianshiba commented 3 years ago

现象描述: 又是一次难得的版本发布,手忙脚乱搞到晚上1点左右,总算发布了,但只要一执行某个操作,立即应用就无法处理请求,浏览器上所有后端请求都处于waitting状态?

mianshiba commented 3 years ago

好吧,对于这样的问题,直接三板斧,首先问题可以重现,但确实没怎么遇到这样的问题,只要执行一个操作,整个应用就立即无法处理请求,只能尝试的,看看系统负载,jvm内存堆栈,线程堆栈。

1、首先应用没有任何异常日志,从日志上很难分析有问题。 2、jvm内存堆栈大致也分析了下,依然没有什么问题。 3、分析线程堆栈,发现了大量的线程http-nio-xxx处于waitting状态,而且数量差不多是200个左右,根据tomcat不能处理请求,记得tomcat默认最多并发处理请求线程数是200,那么解释了tomcat无法处理更多请求。

4、为什么tomcat的线程池为什么都不能释放呢?看代码,发现大量都在druid takelast的方法上阻塞住了。 5、为什么都阻塞在了druid 获取数据库连接池上呢?

理论上,应该会释放呀,而是当时测试环境也没问题,观察了rds的线上监控,没发现什么异常. ..... ..... ...... .....

经过了一些列源码分析,最终的原因出在以下: 1、在controller所在的请求李,使用了线程池,那么就可以并发连接数据库。 2、druid数据源,默认最大并发数据库连接数是8。 3、我们spring boot 应用使用了jpa,而jpa 默认开启了open-in-view配置,即一个controller的request-jdbc-connnection-response的生命周期保持一致,即只有响应返回了,jdbc的连接才释放。 4、而由于我们使用了线程池,而线程池里也有数据库操作,线程池外的连接无法释放,连接内部也在等待,而且druid没有配置maxwait参数等等。

mianshiba commented 3 years ago

以上的只是简单复盘了下这次问题,其实可以写的更深入,只是自己做一个记录而已。