背景
上午刚到公司,准备开始一天的摸鱼之旅时突然收到了一封监控中心的邮件。
心中暗道不好,因为监控系统从来不会告诉我应用完美无 bug
,其实系统挺猥琐。
打开邮件一看,果然告知我有一个应用的线程池队列达到阈值触发了报警。
由于这个应用出问题非常影响用户体验;于是立马让运维保留现场 dump
线程和内存同时重启应用,还好重启之后恢复正常。于是开始着手排查问题。
分析
首先了解下这个应用大概是做什么的。
简单来说就是从 MQ
中取出数据然后丢到后面的业务线程池中做具体的业务处理。
而报警的队列正好就是这个线程池的队列。
跟踪代码发现构建线程池的方式如下:
-
ThreadPoolExecutor executor = new ThreadPoolExecutor(coreSize, maxSize,
-
0L, TimeUnit.MILLISECONDS,
-
new LinkedBlockingQueue<Runnable>());;
-
put(poolName,executor);
采用的是默认的 LinkedBlockingQueue
并没有指定大小(这也是个坑),于是这个队列的默认大小为 Integer.MAX_VALUE
。
由于应用已经重启,只能从仅存的线程快照和内存快照进行分析。
内存分析
先利用 MAT
分析了内存,的到了如下报告。