![0ffdb345b3a66d77b29e4727292c4c7d.png](https://i-blog.csdnimg.cn/blog_migrate/bd692926ef7af53ccdd87a95fa47a613.jpeg)
线上有一个非常繁忙的服务的 JVM 进程 CPU 经常跑到 100% 以上,下面写了一下排查的过程。通过阅读这篇文章你会了解到下面这些知识。
- Java 程序 CPU 占用高的排查思路
- 可能造成线上服务大量异常的 log4j 假异步
- Kafka 异步发送的优化
- On-CPU 火焰图的原理和解读
- 使用 Trie 前缀树来优化 Spring 的路径匹配
开始尝试
JVM CPU 占用高,第一反应是找出 CPU 占用最高的线程,看这个线程在执行什么,使用 top 命令可以查看进程中所有线程占用的 CPU 情况,命令如下所示。
top -Hp you_pid
输出如下:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
48 root 20 0 30.367g 2.636g 12940 S 12.7 2.9 36:15.18 java
2365 root 20 0 30.367g 2.636g 12940 R 1.3 2.9 2:33.64 java
2380 root 20 0 30.367g 2.636g 12940 S 1.3 2.9 2:33.10 java
2381 root 20 0 30.367g 2.636g 12940 S 1.3 2.9 2:33.41 java
10079 root 20 0 30.367g 2.636g 12940 S 1.3 2.9 0:30.73 java
10 root 20 0 30.367g 2.636g 12940 S 1.0 2.9 4:08.54 java
11 root 20 0 30.367g 2.636g 12940 S 1.0 2.9 4:08.55 java
92 root 20 0 30.367g 2.636g 12940 S 1.0 2.9 2:53.71 java
681 root 20 0 30.367g 2.636g 12940 S 1.0 2.9 2:52.56 java
683 root 20 0 30.367g 2.636g 12940 S 1.0 2.9 2:56.81 java
690 root 20 0 30.367g 2.636g 12940 S 1.0 2.9 3:34.24 java
可以看到占用 CPU 最高的线程 PID 为 48(0x30),使用 jstack 输出当前线程堆栈,然后 grep 一下 0x30,如下所示。
jstack 1 | grep -A 10 "0x30 "
输出结果如下。
"kafka-producer-network-thread | producer-1" #35 daemon prio=5 os_prio=0 tid=0x00007f9ac4fc7000 nid=0x30 runnable [0x00007f9ac9b88000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x0000000094ef70c8> (a sun.nio.ch.Util$3)
- locked <0x0000000094ef70e0> (a java.util.Collections$UnmodifiableSet)
- locked <0x000000009642bbb8> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at org.apache.kafka.common.network.Selector.select(Selector.java:686)
可以看到这是一个 kafka 的发送线程。我们的日志打印是使用 log4j2 的 kafka 插件将日志文件写入到 kafka,日志写入量非常大。接下来先来优化这个 kafka 发送线程的 CPU 占用。
Log4j2 下 KafkaAppender 优化
KafkaAppender