最近看了一下部署游戏后台的服务器状况,发现我的一个 Java 程序其占用的 CPU 时长超过 100%,排查后发现竟是 Disruptor 引起的,让我们来看看究竟为什么 Disruptor 会有这样的表现。
<!– more –>
发现占用 CPU 时间超过 100% 的进程
首先是在服务器上用 top 命令查看服务器状态,发现有一个应用程序占用的 CPU 时长超过 100%,如图:
我根据进程号查了一下,发现是我的一个 Java 游戏后台服务,有一个 CPU 几乎被占满,因此继续排查究竟是什么代码导致了这种情况。
用 top -Hp 27538
将这个进程的所有线程显示出来,按照 CPU 占用时间排序,看到了这个结果:
27658 线程占用了近乎所有的 CPU 时间,而且一直都是,因此查看这个进程的详细信息。
用 jstack pid > pid.log
命令将该进程的进程快照输出到一个文件中,下载下来。
将 27658 转换为 16 进制 0x6c0a 后在线程快照中查询(因为线程快照中线程 ID 都是 16 进制存放,所以需要转换):
"disruptor-0" #27 prio=5 os_prio=0 tid=0x00007fa100c58000 nid=0x6c0a runnable [0x00007fa0ae080000]
java.lang.Thread.State: RUNNABLE
at com.lmax.disruptor.BusySpinWaitStrategy.waitFor(BusySpinWaitStrategy.java:39)
at com.lmax.disruptor.ProcessingSequenceBarrier.waitFor(ProcessingSequenceBarrier.java:56)
at com.lmax.disruptor.BatchEventProcessor.processEvents(BatchEventProcessor.java:159)
at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:125)
at java.lang.Thread.run(Thread.java:748)
这是 Disruptor 的一个堆栈,为了更直观地查看线程的状态信息,可以将快照上传到专门的分析平台上。
(博主本人对于进程快照分析也是处于新手阶段,如果大家有什么建议或者意见,欢迎在下方留言。)
分析 Disruptor 为何会占用整个 CPU
根据上面快照的分析,实际是 Disruptor 的等待策略相关的线程所导致的,查看 BusySpinWaitStrategy
类,发现有相关说明:
* This strategy will use CPU resource to avoid syscalls which can introduce latency jitter. It is best
* used when threads can be bound to specific CPU cores.
现在终于知道了,原来是因为这个策略就是让线程绑定了一个 CPU 核心,自然其 CPU 占用时间就超过 100% 了。
总结
通过这一次问题的排查,不仅了解了 linux 系统中进程、线程的关系,也开始着手 java 服务的线上排查,顺便也回顾了一下之前有过接触的 Disruptor。如果大家有什么建议或者意见,欢迎在下方留言。
有兴趣的话可以关注我的公众号,说不定会有意外的惊喜。