一次线程阻塞问题的分析与解决

叁叁肆2018-09-19 14:13

本文来自网易云社区

作者:苏鹏


最近部门的某产品周末时候测试服务器下会无故宕机,周一测试的同学来问具体原因,综合周末收到的哨兵系统的报警,简单分析了现象,应该是后台服务的原因。


1.首先登录哨兵系统,查看我们部署的服务的状态
此处内存、硬盘等指标都是比较正常的水平,但是CPU在某一个时间段非常高,所以初步判断是CPU异常导致了服务宕机(此处应有CPU状态异常图,但是当时没有把事故现场保存下来)


2.登录服务器,查看服务器状态
(1) 查看日志
登录部署服务的两台服务器,查看我们部署的两台服务器的日志,果然发现日志里报了oom的错误
(2)使用top命令
      使用top命令,也能看到本服务的CPU占用率会井喷
      图略,现象是该服务的CPU占用率为99%
结论:已经能定位到是内存溢出的问题,时间点也比较符合服务宕机的时间,这时候就该寻找具体是什么原因造成了oom

3. dump内存文件

在项目部署的时候需要加上一个参数,即-XX:+HeapDumpOnOutOfMemoryError,等OOM的时候会把内存文件DUMP出来

这时候我们发现内存文件已经生成在我们设置的路径下了


4.使用java visualVM分析该内存文件

(1)使用scp命令把该内存文件下载到本地,具体操作略

(2)打开java visualVM应用

我用的是mac系统,不熟悉的小伙伴可能不知道它存在的位置,这里也给大家写一下jdk自带工具的路径

/Library/java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin

  (3)导入内存文件后,在java visualVM中可以看到该文件的简介

我们可以看到我们的visualVM已经为我们展示了各个线程的状态。

然后搜索一下状态为BLOCK状态的线程

我们发现BLOCK状态的线程,它们所指向的代码都是同一个,MMLogger是我们封装的日志文件,难道会出什么问题?


5.分析代码

定位到我们具体的代码问题,那我们接下来就来分析代码,我们发现了两个问题

(1)在AOP中我们配置了所有进入接口都会打印一个日志

     execution(public * com.netease.ai.ar.dongjian.web..*.* (..))"

(2)使用日志的方式不正确

        我们使用的是 org.apache.log4j.LogManager;


其中跟踪代码下去,就会发现会进入到这个方法

会有这样的一个代码段有关键字,在并发量比较高的情况下可能会出现死锁的情况

总结:综合以上两个原因,就会造成同时会有很多线程在打印日志,而打印日志又会进入到synchronize代码段,造成很多的线程都在等待这段代码执行完,导致了BLOCK的产生

以上两个方面,我们分别解决

(1)把进入所有接口日志配置去除,改成有需要的接口加日志注解的方式

(2)修改日志类,改为org.slf4j.LoggerFactory;



网易云免费体验馆0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区