后端开发 - 记一次生产问题定位
@auther 张念磊
@date 2020/7/25
问题描述
一个服务上线生产之后两天出现了三次问题
详细征兆如下:
- 刚出现此问题时,浏览器的一个请求发过去,开发者工具network一栏显示该请求状态一直是padding,会持续几分钟。
- 网关服务打印了对应的请求。
- 后台服务只打印了controller中的日志,没有打印service层的日志(日志级别debug,服务正常时会打印service层的日志);
- 通过重启服务可暂时解决该问题,不过一段时间后会复现。
可能的原因
前提:近期用户增多,有49家机构在使用该功能模块。
- 服务器线程爆了:该服务器一共部署了31个微服务,还有一些对外提供的的其他服务,服务的总线程数量超过计算机的最大线程数量。
- 服务器内存不够:服务器内存为32GB,现有未使用1GB(每个服务的运行内存设置为300M/512M/1G)。但服务日志没有爆出内存溢出异常,不能断定是该问题。
- 编写的代码异常导致,但异常时服务不产生日志,无法定位问题。以前也会有此问题,程序异常,后台返回的异常原因是null,可能是该服务的config配置有误,没有准确捕捉并返回异常信息。
尝试解决
- 减小其他服务启动时配置的内存大小,使服务器内存处于健康状态 (已使用该方法,未能解决问题)
- 限制每个微服务的线程数量,使其不能超过计算机的最大线程数。(经排查,服务的线程数已被限制,每个服务被限制为200,Linux系统的总线程数为13万,故排除此原因)
- 为服务添加合理的全局异常捕获机制。(查看该工程的启动类中的try-catch代码块,发现catch到异常后直接返回null,没有做任何处理,在此为其添加一行代码,记录捕获到的异常到日志中)
- 找同事协助分析。
定位到问题
log文件被锁住导致程序无响应。具体原因:应为项目中使用到了两种打印日志的方式,一是使用第三方的slf4j打印log;二是使用printStackTrace()函数打印日志
最后
此次生产问题的原因:
- 日志文件被锁住了。printStackTrace()函数打印日志,和使用slf4j打印日志时对日志文件资源的抢夺,导致文件被锁住;
- 启动类中捕获了异常但是没有打印异常
目前的解决办法:启动类中添加异常信息的打印;删除代码中使用printStackTrace()函数的地方,改为使用slf4j打印log;
可用的其他办法:添加配置,在配置中设置只允许slf4j打印日志,不允许使用printStackTrace()函数打印日志。
补充
本次排查问题用到的知识
查看系统总线程数
/proc/sys/kernel/pid_max #查系统支持的最大线程数
查看进程下的所有线程数
先用 jps -l 查看应用的PID
jps -l
查看该Pid(进程)下的线程数
ps -Lf {pid} | wc -l
管道统计
| wc -l
解压jar包 (可查看源码)
jar -xvf test.jar
view jstack.log
后续
这个问题算是解决了,但是我还是有几个好奇的地方:
- 如何定位到的问题?
- 定位此类问题的思路和方法?
- jstack命令 如何使用?
思路:
- 以jstack为突破点,了解一下java堆栈分析
- 请教同事
下一篇博客预告:
使用jstack定位问题原因
阿里巴巴的arthas是什么?如何使用它定位生产问题?