前面给大家讲过一次 OOM 的优化排查实战,今天再给大家讲一个 CPU 100% 优化排查实战。
收到运维同学的报警,说某些服务器负载非常高,让我们开发定位问题。拿到问题后先去服务器上看了看,发现运行的只有我们的 Java 应用程序。于是先用 ps
命令拿到了应用的 PID
。
ps:查看进程的命令;PID:进程 ID。
ps -ef | grep java
可以查看所有的 Java 进程。前面也曾讲过。
接着使用 top -Hp pid
将这个进程的线程显示出来。输入大写 P 可以将线程按照 CPU 使用比例排序,于是得到以下结果。
果然,某些线程的 CPU 使用率非常高,99.9% 可不是非常高嘛(😂)。
为了方便问题定位,我立马使用 jstack pid > pid.log
将线程栈 dump
到日志文件中。关于 jstack 命令,我们前面刚刚讲过。
我在上面 99.9% 的线程中随机选了一个 pid=194283
的,转换为 16 进制(2f6eb)后在线程快照中查询:
线程快照中线程 ID 都是16进制的。
发现这是 Disruptor
的一个堆栈,好家伙,这不前面刚遇到过嘛,老熟人啊, 强如 Disruptor 也发生内存溢出?
真没想到,再来一次!
为了更加直观的查看线程的状态,我将快照信息上传到了专门的分析平台上:http://fastthread.io/,估计有球友用过。
其中有一项展示了所有消耗 CPU 的线程,我仔细看了下,发现几乎都和上面的堆栈一样。
也就是说,都是 Disruptor
队列的堆栈,都在执行 java.lang.Thread.yield
。
众所周知,yield
方法会暗示当前线程让出 CPU
资源,让其他线程来竞争(多线程的时候我们讲过 yield,相信大家还有印象)。
根据刚才的线程快照发现,处于 RUNNABLE
状态并且都在执行 yield
的线程大概有 30几个。
初步判断,大量线程执行 yield
之后,在互相竞争导致 CPU 使用率增高,通过对堆栈的分析可以发现,确实和 Disruptor
有关。
好家伙,又是它。
既然如此,我们来大致看一下 Disruptor
的使用方式吧。看有多少球友使用过。
第一步,在 pom.xml 文件中引入 Disruptor
的依赖:
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
第二步,定义事件 LongEvent:
public static class LongEvent {
private long value;
public void set(long value) {
this.value = value;
}
@Override
public String toString() {
回复