背景
因为tomcat的http线程池,默认是200, 如果线程池耗尽,则会出现无法提供服务的情况。
故障模拟
某些情况下,可能http的TPS不高,但是内部程序有bug,导致了tomcat的http线程池的卡死。本文将会总结1分钟内排查出问题的方法。以下为示例:
假设有一个Controller方法,模拟调用某个业务:
@RestController
@RequestMapping("/biz")
public class BizController {
@GetMapping("/fire")
public String fire(){
return RpcInvoker.getUserInfo();
}
}
模拟业务的代码,这段逻辑中,readline里面是有锁的保护,不允许并发读取:
public class RpcInvoker {
public static String getUserInfo(){
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
return "done";
}
}
此时,使用ApiPost进行批量调用,或者 PostMan也行,我比较喜欢用ApiPost,使用【一键压测】功能,并发数超过200,举例:改到300。
点击压测后,马上就会发现,不能正常执行完请求。浏览器访问 /biz/fire 也无响应,此时模拟了tomcat的卡死。那么故障已经发生,现在需要马上定位问题。
线程dump
执行 jps -l 列出全部的java进程
找到目标的SpringBootTomcatMain的java进程,pid是 34280,
执行 jstack -l 34280 > stack.log 导出当前堆栈信息,但是堆栈信息内容很多,一般大小超出1M,很难直接肉眼查看。
jstack堆栈分析
- 打开 http://ctbots.com
- 打开jstack的堆栈分析 日志上传页面:
- 上传堆栈文件,点击【开始分析】,分析出基本信息。
环境信息
展示了基本的dump的基本要素,包括:导出时间和JVM的版本。
线程状态及阻塞原因
我们主要关注是否存在BLOCK状态的线程(图中,我们发现了大量的BLOCK线程)。
点击按钮,查看线程详情:
确定被卡主的源头,点击【被别人卡住】 马上看到被block的原因:
调用分析
当tomcat卡死时,如何判断高频调用,线程都执行在什么地方,可以点击【调用分析】,这里马上注意到我们的模拟的业务代码,大量在的出现在线程中:
点击查看,发现全部被BLOCK掉,所以 调用会出现这么多次。
至此,我们就能快速地在1分钟内 分析完tomcat卡死的原因了。