记一次生产问题排查-unirest 导致的线程泄露
1.问题现象
某次迭代内容上线后服务线程激增,临时激增也还行,但是线程数量一直不讲下去,开始排查问题。
2.分析问题
2.1 线上linux下使用jstack [pid] > thread.dump 命令 生成线程分析文件
2.2 将生成的dump 文件下载到本地准备分析,因为我们服务用的k8s,所以本地terminal我用的如下命令来完成这个动作
kubectl cp [namespace]/[pod]:/data/apps/thread.dump /Users/xxx/thread.dump
2.3 使用TDA工具分析thread.dump文件,TDA下载地址:https://mkbrv.github.io/tda/
2.3.1 tda打开并且导入文件后如图所示:
2.3.2 然后挨个查看条目,发现如下不正常的情况:
2.3.3 点击一个进去查看如下:
2.3.4 感觉unirest有嫌疑,随网上查看unirest是否有线程泄漏问题,结果还真有。com.mashape.unirest » unirest-java 这个早就不维护了,
我是调用接口前自定义了unirest的超时时间,结果每次通过unirest调用接口就会额外创建一个线程,导致线程激增,并且一直处于TIMED_WAITING状态。
3.解决问题
3.1 不自己定义超时时间了,一切都采用默认配置,就不会有这个问题,适用于紧急解决问题
3.2 更换unirest包为com.konghq » unirest-java,这个解决了线程泄漏的问题,但是也删除了老的unirest的一些没必要存在的api,升级后需要自行根据情况调整,参考如下:
unirest官方文档
升级unirest注意点
这里特地说下我升级后超时时间的配置:
因为unirest建议配置的话最好只做一次,不建议多次reset,所以我在项目启动的application中直接加入的unirest的配置
Unirest.config().socketTimeout(120000).connectTimeout(10000);
@PostConstruct
public void initApplication() {
Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
if (activeProfiles.contains(DukangConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles
.contains(DukangConstants.SPRING_PROFILE_PRODUCTION)) {
log.error("You have misconfigured your application! It should not run "
+ "with both the 'dev' and 'prod' profiles at the same time.");
}
if (activeProfiles.contains(DukangConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles
.contains(DukangConstants.SPRING_PROFILE_CLOUD)) {
log.error("You have misconfigured your application! It should not "
+ "run with both the 'dev' and 'cloud' profiles at the same time.");
}
Unirest.config().socketTimeout(120000).connectTimeout(10000);
}
当然你可以在任何一个静态代码块中加入这个配置,只要保证项目启动的时候配置代码只执行一次就好。
4.结语
此篇文章全当自己的一个解决线上问题的记录,方变后续温故而知新,各位有更好的解决方案欢迎指出,谢谢!