其他分享
首页 > 其他分享> > 线上CPU飙升排查

线上CPU飙升排查

作者:互联网

线上CPU飙升排查

目录

准备一份代码

public class Main {

    public static void main(String[] args) {
        int i = 0;
        while (true) {
            i++;
            i--;
        }
    }
}

步骤

top命令找到对应进程

top

image

找到占用最高的线程

方法1

top -Hp 506

image

方法2

ps -mp 506 -o THREAD,tid,time

image

linux下的线程号是10进制,而jdk自带工具中的线程号使用的是16进制,我们需要先把它转换成16进制

将线程号转换成16进制

print "%x\n" 507
# 1fb

使用jdk的工具jstack查看堆栈信息

-A100表示最多显示100行

jstack 506 | grep 1fb -A100

image

我们看到上面直接定位到了,main方法的第7行

如果是那种多线程代码,我们要给线程池中的线程命名,这样便于我们排查到对应代码,这里仅仅作为示范

cpu飙升可能原因

1. 超大对象频繁移动或者创建

超大对象频繁在年轻代中移动,消耗CPU性能

解决思路

  1. 考虑直接将对象放到老年代
  2. 对象能复用则复用,可以使用对象池,避免频繁创建大对象

2 .内存消耗过大,导致Full GC次数过多

我们会在top命令中排查到GC线程的CPU很高,

这样可以使用jstat工具查看GC次数,确认是否为Full GC过多

jstat gcutil 进程id  间隔时间 统计次数

# 样例 jstat -gcutil 506 10 10

image

也可以通过查看老年代的情况判断

jdk 8使用如下命令

jmap -heap 进程id

jdk 9以后使用如下命令

jhsdb jmap --pid 进程id --heap
➜  emmith jhsdb jmap --pid 506 --heap
Attaching to process ID 506, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 17.0.3+7-LTS

using thread-local object allocation.
Garbage-First (G1) GC with 8 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 3309305856 (3156.0MB)
   NewSize                  = 1363144 (1.2999954223632812MB)
   MaxNewSize               = 1983905792 (1892.0MB)
   OldSize                  = 5452592 (5.1999969482421875MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 22020096 (21.0MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 2097152 (2.0MB)

Heap Usage:
G1 Heap:
   regions  = 1578
   capacity = 3309305856 (3156.0MB)
   used     = 14659584 (13.98046875MB)
   free     = 3294646272 (3142.01953125MB)
   0.4429806321292776% used
G1 Young Generation:
Eden Space:
   regions  = 6
   capacity = 25165824 (24.0MB)
   used     = 12582912 (12.0MB)
   free     = 12582912 (12.0MB)
   50.0% used
Survivor Space:
   regions  = 0
   capacity = 0 (0.0MB)
   used     = 0 (0.0MB)
   free     = 0 (0.0MB)
   0.0% used
G1 Old Generation:
   regions  = 2
   capacity = 186646528 (178.0MB)
   used     = 2076672 (1.98046875MB)
   free     = 184569856 (176.01953125MB)
   1.112622893258427% used

解决思路

  1. 增大堆空间,增大老年代
  2. 将对象放到堆外内存,减少GC
  3. 代码里面可能有System.gc()显示调用,禁用此功能

3. 死循环等CPU密集型代码

代码中可能存在死循环、或者CAS使用不当、或者无线递归

解决思路

  1. 优化代码逻辑,尽量避免无线递归和死循环
  2. 减少CAS次数,或者适当让线程睡眠,如果线程资源竞争特别激烈的情况,将CAS改为使用锁,避免太多的CPU空转

4. 死锁

死锁可以在jstack命令中看到,grep deadlock可以排查是否有死锁

解决思路

如果存在死锁,考虑代码逻辑问题,避免不正确的锁申请顺序

5. 流量激增

集群中别的负载均衡的机器都挂了,请求全部打到某条机器上,导致CPU飙升

解决思路

  1. 限流,熔断降级
  2. 异地多活,保证高可用

参考

https://www.cnblogs.com/dennyzhangdd/p/11585971.html
https://juejin.cn/post/6844904089705250829

标签:used,MB,代码,排查,线程,线上,GC,CPU
来源: https://www.cnblogs.com/emmith/p/16467328.html