一次线上服务CPU100%的排查过程

简介: 文章记录了一次线上服务CPU使用率达到100%的排查过程,通过使用top命令和jstack工具确定了导致高CPU使用的线程,并分析了Disruptor组件的不当配置是问题原因,通过修改组件的策略成功解决了问题。

前言

突然收到线上服务cpu达到100%的报警短信,于是立即展开排查。

排查过程

理论步骤

一、找到最耗CPU的进程
工具:top
方法:
执行top -c ,显示进程运行信息列表
键入P (大写p),进程按照CPU使用率排序

二:找到最耗CPU的线程
工具:top
方法:
top -Hp PID,显示一个进程的线程运行信息列表
键入P (大写p),线程按照CPU使用率排序

三:将线程PID转化为16进制
工具:printf
之所以要转化为16进制,是因为堆栈里,线程id是用16进制表示的。

四:查看堆栈,找到线程在干嘛
工具:pstack/jstack/grep
打印进程堆栈 通过线程id,过滤得到线程堆栈

实战操作

零,发现服务器上安装的不知一个Java版本,于是首先确定下,通过如下 命令。

[root@service-dev ~]# find / -name java
/etc/java
/etc/pki/java
/etc/pki/ca-trust/extracted/java
/etc/alternatives/java
/var/lib/alternatives/java
/usr/share/java
/usr/bin/java
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre/bin/java
/usr/lib/java

一,找到耗CPU进程PID
通过top -c命令,可以发现进程PID 29812消耗的CPU明显是最多

二,找出耗CPU的线程
可以利用ps命令

[root@service-dev ~/consume-service]# ps -mp 29812 -o THREAD,tid,time
USER     %CPU PRI SCNT WCHAN  USER SYSTEM   TID     TIME
root     96.3   -    - -         -      -     - 00:01:04
root      0.0  19    - futex_    -      - 29812 00:00:00
root      9.2  19    - futex_    -      - 29813 00:00:06
root      1.2  19    - futex_    -      - 29814 00:00:00
root      0.0  19    - futex_    -      - 29815 00:00:00
root      0.0  19    - futex_    -      - 29816 00:00:00
root      0.0  19    - futex_    -      - 29817 00:00:00
root     12.5  19    - futex_    -      - 29818 00:00:08
root      3.5  19    - futex_    -      - 29819 00:00:02
root      0.0  19    - futex_    -      - 29820 00:00:00
root      0.0  19    - futex_    -      - 29821 00:00:00
root      0.0  19    - futex_    -      - 29833 00:00:00
root      0.0  19    - futex_    -      - 29834 00:00:00
root      0.0  19    - futex_    -      - 29836 00:00:00
root     87.9  19    - -         -      - 29840 00:00:44
root      0.0  19    - ep_pol    -      - 29841 00:00:00
root      0.0  19    - ep_pol    -      - 29842 00:00:00
root      0.0  19    - ep_pol    -      - 29843 00:00:00

可以明显发现线程29840占用的CPU最多。

当然,也可以通过top -Hp pid命令,将这个进程的线程显示出来。输入大写的 P 可以将线程按照 CPU 使用比例排序。

三,将10进制线程ID转换为16进制,便于后续在堆栈grep

[root@service-dev ~/consume-service]# printf "%x\n" 29840
7490

四、打印堆栈并grep除目标线程

[root@service-dev ~/consume-service]# jstack 29812 | grep ‘0x7490’ -C5 --color
"disruptor-Disruptor Main--1" #14 prio=5 os_prio=0 tid=0x00007f9038952800 nid=0x7490 runnable [0x00007f9011ad4000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.Thread.yield(Native Method)
        at com.lmax.disruptor.YieldingWaitStrategy.applyWaitMethod(YieldingWaitStrategy.java:58)
        at com.lmax.disruptor.YieldingWaitStrategy.waitFor(YieldingWaitStrategy.java:40)
        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)

   Locked ownable synchronizers:
        - None

明显,可以发现是服务使用的Disruptor组件在执行YieldingWaitStrategy策略的时候,导致了CPU升高,排查的方向就很聚焦了。

四、进入业务排查Disruptor组件使用配置
1, 简单分析
业务层面:因为这个这本身是一个消费服务,消费来自RocketMQ的消息,但是稍显不合理的地方是一个Disruptor消费者处理了多个Topic业务,鉴于最近短时业务比较多,长时业务变少,所以yield的频率明显升高。
Disruptor层面:目前采用的时YieldingWaitStrategy策略,该策略是一种充分利用CPU 的策略,使用自旋 + yield的方式来提高性能。当消费线程(Event Handler threads)的数量小于 CPU 核心数时推荐使用该策略。我这边业务上同时启动的消费者线程数量明显多于4核个数,不太合理。
2,着手处理
短期处理:修改WaitStrategy策略,降低对CPU的使用。

  1. BlockingWaitStrategy:(也是默认的策略):使用的是锁的机制,其对CPU的消耗最小并且在各种不同的部署环境中能提供更加一致性的表现。
  2. SleepingWaitStrategy:在多次循环尝试不成功后,选择让出CPU,等待下次调度,多次调度后仍不成功,尝试前睡眠一个纳秒级别的时间再尝试,这种策略平衡了延迟和CPU资源占用,但延迟不均匀。
  3. YieldingWaitStrategy:无所高性能策略,在多次循环尝试不成功后,选择让出CPU,等待下次调。平衡了延迟和CPU资源占用,但延迟也比较均匀。官方对 YieldingWaitStrategy 的描述里谈道:
    当消费线程(Event Handler threads)的数量小于 CPU 核心数时推荐使用该策略。

所以,暂时调整为低消耗CPU的BlockingWaitStrategy,重新部署后解决了CPU升高问题,对业务的延迟影响也较小。

长远处理
将我们现有的业务拆分,根据不同的业务需要采用不同的消费策略。

参考

https://www.imooc.com/article/259253
https://www.cnblogs.com/lishijia/p/5549980.html 100%分析
https://blog.csdn.net/jiangzhexi/article/details/77429671 100%
https://www.cnblogs.com/crossoverJie/p/10129072.html 100%分析 Disruptor
https://crossoverjie.top/2018/08/29/java-senior/OOM-Disruptor/ Disruptor的坑
https://www.cnblogs.com/lyhero11/p/5127054.html
https://fastthread.io/

相关文章
|
7月前
|
监控 Java 索引
cpu使用率过高和jvm old占用过高排查过程
cpu使用率过高和jvm old占用过高排查过程
179 2
|
4月前
|
小程序 JavaScript Java
【Java】服务CPU占用率100%,教你用jstack排查定位
本文详细讲解如何使用jstack排查定位CPU高占用问题。首先介绍jstack的基本概念:它是诊断Java应用程序线程问题的工具,能生成线程堆栈快照,帮助找出程序中的瓶颈。接着,文章通过具体步骤演示如何使用`top`命令找到高CPU占用的Java进程及线程,再结合`jstack`命令获取堆栈信息并进行分析,最终定位问题代码。
403 1
【Java】服务CPU占用率100%,教你用jstack排查定位
|
4月前
|
监控 安全 算法
在Linux中,cpu使用率过高可能是什么原因引起的?排查思路是什么?
在Linux中,cpu使用率过高可能是什么原因引起的?排查思路是什么?
|
4月前
|
Java
靠这三步就能排查CPU占用100%?
靠这三步就能排查CPU占用100%?
174 0
|
6月前
|
监控 Serverless 应用服务中间件
Serverless 应用引擎操作报错合集之使用自定义镜像部署GPU服务时,报错 "CPU is required but not provided",是什么导致的
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
5月前
|
缓存 弹性计算 监控
云服务器 CPU 使用率高的问题排查与优化
云服务器 CPU 使用率高的问题排查与优化
445 0
|
6月前
|
SQL Java Linux
Linux系统cpu飙升到100%排查方案
Linux系统cpu飙升到100%排查方案
501 0
|
7月前
|
SQL 运维 NoSQL
【Redis 故障排查】「连接失败问题排查和解决」带你总体分析CPU及内存的使用率高问题排查指南及方案
【Redis 故障排查】「连接失败问题排查和解决」带你总体分析CPU及内存的使用率高问题排查指南及方案
221 0
|
7月前
|
监控 Java Linux
疯狂飙高!怎么排查CPU导致系统反应缓慢的问题?
疯狂飙高!怎么排查CPU导致系统反应缓慢的问题?
140 0
|
19天前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
54 7