CPU飙升100%,如何定位排查问题。top,ps查看进程信息的回答,已经不能让人满意了。


前言

工作几年了,最近面试CPU飙升至100%的问题,居然说不出个二五八万来,关键是二面和一面问题差不多,一面的人这么给机会,我一面后居然没有认真复盘。开诚布公的问我,你为什么二面和一面回答的差不多,没有任何提升呢。真是让人老脸一红,丢人丢到家了。


一、CPU为什么飙升?

  1. 无限循环或者高频计算
    很常见的问题,代码错误,逻辑问题,高频计算任务。
  2. 资源分配不合理
    现在的AI或者大数据运算,高峰期没有合理的分配资源。
  3. 锁竞争
    死锁双方互相等待对方释放资源,无限循环,不拿对对方的资源不罢休。
  4. 大量的并发线程的问题
    解决一个问题用了100个线程,频繁的进行CPU上下文的切换。
  5. 内存不足
    会将磁盘存储作为虚拟内存使用,这种虚拟内存运行速度很慢。过度的分页和交换会导致CPU占用率居高不下
  6. 频繁的垃圾回收
    垃圾回收会占用大量的CPU资源,对象频繁创建与销毁
  7. 内存泄露
    可用内存减少,频繁的GC操作。

二、如何定位排查(java进程)

定位进程

使用top命令,可以看到信息分为两部分

lyl@localhost:~$ top

top - 18:26:30 up 50 min,  2 users,  load average: 2.21, 1.07, 0.63
Tasks: 354 total,   2 running, 352 sleeping,   0 stopped,   0 zombie
%Cpu(s): 47.6 us, 11.8 sy,  0.0 ni, 39.7 id,  0.0 wa,  0.8 hi,  0.1 si,  0.0 st 
MiB Mem :  15698.0 total,  10678.5 free,   3596.7 used,   1790.9 buff/cache     
MiB Swap:   8032.0 total,   8032.0 free,      0.0 used.  12101.3 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                   
  10187 lyl       20   0  506472  36964  30556 R  98.7   0.2   3:00.92 vmtoolsd                                  
  93082 lyl       20   0 7314356  87452  31900 S  98.3   0.5   1:10.66 java                                      
  22301 lyl       20   0 3158644 512336 117020 S  20.6   3.2   1:15.47 ptyxis                                    
   8676 lyl       20   0 5403608 428772 138056 S  12.0   2.7   1:03.01 gnome-shell                               
  84554 root      20   0       0      0      0 I   2.0   0.0   0:00.61 kworker/u516:3-events_unbound             
   1726 root      20   0 3444640  97112  55940 S   0.3   0.6   0:16.05 dockerd                                   
   2635 root      20   0 1238496  17868  10536 S   0.3   0.1   0:10.43 containerd-shim                           
   7553 lyl       20   0    6592   4288   2368 S   0.3   0.0   0:00.20 dbus-broker                               
   8688 1001      20   0   10.7g  65392  46008 S   0.3   0.4   0:05.40 next-server (v1                           
  93341 lyl       20   0  232248   5944   3768 S   0.3   0.0   0:00.11 top                                       
  94338 lyl       20   0  232248   6036   3860 R   0.3   0.0   0:00.02 top                                      
### 第一部分:系统的总体情况,CPU、内存、交换空间的使用情况,进程数量和负载
us:1.3%的CPU时间被用户空间的进程(用户程序)占用
sy:1.2%的CPU时间被内核空间的进程占用
ni:0.0%的CPU时间被改变优先级的进程占用(优先级调整)
id:97.1%的CPU时间处于空闲状态
wa:0.0%的CPU时间等待I/O操作
hi:0.3%的CPU时间用于硬件中断
si:0.2%的CPU时间用于软件中断
st:0.0%的CPU时间被虚拟化环境占用(如果是虚拟机中运行的话)
后面的是总内存,空闲内存,已使用的内存,缓存和缓冲区的内存。

### 第二部分:总内存,空闲内存,已使用的内存,缓存和缓冲区的内存。
进程唯一标识,CPU和内存的使用情况,运行时间,进程的名称或者可执行文件名
  • us和ni占用高,说明用户态进程占用了较多的CPU,所以应该重点排查进程的性能问题。
  • 系统CPU高,说明内核态占用了较多的CPU,重点排查内核进程和系统调用的问题
  • I/O等待CPU高,说明等待I/O的时间比较长,应该重点排查是不是出现了I/O的问题
  • 软终端和硬中断高,说明中断的处理程序占用了较多的CPU,应该重点排序中断服务程序

定位进程中CPU占用率最高的线程

top -Hp pid 查看进程下面每个线程的CPU使用情况

lyl@localhost:~$ top -Hp 93082

top - 18:27:55 up 51 min,  2 users,  load average: 2.28, 1.37, 0.78
Threads:  21 total,   1 running,  20 sleeping,   0 stopped,   0 zombie
%Cpu(s): 47.9 us, 12.1 sy,  0.0 ni, 39.2 id,  0.0 wa,  0.8 hi,  0.1 si,  0.0 st 
MiB Mem :  15698.0 total,  10678.6 free,   3596.6 used,   1790.9 buff/cache     
MiB Swap:   8032.0 total,   8032.0 free,      0.0 used.  12101.3 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                   
  93083 lyl       20   0 7314356  87452  31900 R  98.7   0.5   2:34.71 java                                      
  93082 lyl       20   0 7314356  87452  31900 S   0.0   0.5   0:00.00 java                                      
  93084 lyl       20   0 7314356  87452  31900 S   0.0   0.5   0:00.00 GC Thread#0                               
  93085 lyl       20   0 7314356  87452  31900 S   0.0   0.5   0:00.00 G1 Main Marker                            
  93086 lyl       20   0 7314356  87452  31900 S   0.0   0.5   0:00.00 G1 Conc#0                                 
  93087 lyl       20   0 7314356  87452  31900 S   0.0   0.5   0:00.00 G1 Refine#0                               
  93088 lyl       20   0 7314356  87452  31900 S   0.0   0.5   0:00.00 G1 Service                                
  93091 lyl       20   0 7314356  87452  31900 S   0.0   0.5   0:00.05 VM Periodic Tas           

线程PID十进制转换为16进制

top打印的十进制的,但是jstack打印的是十六进制的。
printf “%x\n” PID

lyl@localhost:~$ printf "%x\n" 93082
16b9a

使用jstack打印堆栈信息

lyl@localhost:~$ jstack 93082|greo 16b9a
Full thread dump Java HotSpot(TM) 64-Bit Server VM (17.0.12+8-LTS-286 mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x00007f7e58004bd0, length=11, elements={
0x00007f7f38023c90, 0x00007f7f38170d80, 0x00007f7f38172170, 0x00007f7f38177740,
0x00007f7f38178b00, 0x00007f7f38179f20, 0x00007f7f3817b8e0, 0x00007f7f3817ce20,
0x00007f7f38186290, 0x00007f7f38191980, 0x00007f7f381bec10
}

"main" #1 prio=5 os_prio=0 cpu=266723.38ms elapsed=272.87s tid=0x00007f7f38023c90 nid=0x25cf2 runnable  [0x00007f7f3d5fd000]
   java.lang.Thread.State: RUNNABLE
        at Cpu_100.main(Cpu_100.java:7)
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@17.0.12/Native Method)
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@17.0.12/NativeMethodAccessorImpl.java:77)
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@17.0.12/DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(java.base@17.0.12/Method.java:568)
        at com.sun.tools.javac.launcher.Main.execute(jdk.compiler@17.0.12/Main.java:419)
        at com.sun.tools.javac.launcher.Main.run(jdk.compiler@17.0.12/Main.java:192)
        at com.sun.tools.javac.launcher.Main.main(jdk.compiler@17.0.12/Main.java:132)

三、其他方式(非java程序)

pstack

采用pstack来查看某个进程的堆栈耿总情况,不需要附加到进程,因此不需要调试权限,只能显示当前对战的快照

lyl@localhost:~$ pstack 255949
Thread 23 (Thread 0x7f1184b3f6c0 (LWP 256100) "G1 Refine#1"):
#0  0x00007f11abdc39be in __futex_abstimed_wait_common () from /lib64/libc.so.6
#1  0x00007f11abdcefa0 in __new_sem_wait_slow64.constprop.0 () from /lib64/libc.so.6
#2  0x00007f11ab6b7622 in PosixSemaphore::wait() () from /usr/local/java/jdk-17.0.12/lib/server/libjvm.so
#3  0x00007f11ab0e00bc in G1ConcurrentRefineThread::run_service() () from /usr/local/java/jdk-17.0.12/lib/server/libjvm.so
#4  0x00007f11aafccb8b in ConcurrentGCThread::run() () from /usr/local/java/jdk-17.0.12/lib/server/libjvm.so
#5  0x00007f11ab7b4636 in Thread::call_run() () from /usr/local/java/jdk-17.0.12/lib/server/libjvm.so
#6  0x00007f11ab6038c1 in thread_native_entry(Thread*) () from /usr/local/java/jdk-17.0.12/lib/server/libjvm.so
#7  0x00007f11abdc711a in start_thread () from /lib64/libc.so.6
#8  0x00007f11abe37c3c in clone3 () from /lib64/libc.so.6

gdb

gdb来附加到该进程并查看其堆栈信息

gdb -p 255950
(gdb) info threads
(gdb) thread <n>
(gdb) bt

cat

Linux提供的接口,只显示主线程当前正在执行的内核栈

lyl@localhost:~$ cat /proc/255949/stack
[<0>] futex_wait_queue+0x65/0x90
[<0>] __futex_wait+0x151/0x1c0
[<0>] futex_wait+0x79/0x120
[<0>] do_futex+0xcb/0x190
[<0>] __x64_sys_futex+0x127/0x1e0
[<0>] do_syscall_64+0x7d/0x160
[<0>] entry_SYSCALL_64_after_hwframe+0x76/0x7e

strace

产看当前进程卡在那个系统调用

lyl@localhost:~$ strace -p 255949
strace: Process 255949 attached
futex(0x7f11aa951990, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, 255950, NULL, FUTEX_BITSET_MATCH_ANY

四、日志文件

其实出现任何问题无论是CPU和内存,都依赖强大的日志系统。像Linux的运行情况,都是会记录在/proc目录下面,日志文件大多数放在/var/log下面。如何中间件众多,比如大数据系统,如果没有日志系统,或者说不能良好的运用日志,出现问题,将寸步难行。还有一个比较重要的dump文件。dump文件用于存储系统崩溃时内存数据的文件。如果程序崩溃了,需要使用到dump文件。默认存在于/var/crash目录下面。

总结

线上的问题大部分都是CPU和内存综合来看去判断问题。CPU飙升,主要是因为上下文切换频繁、多线程、计算密集等原因。现在还有很多成熟的监控工具,基本出了问题就会以信息、邮件、电话的方式,提醒负责人。并将详细的堆栈信息展示出来。

  • /proc是什么,为什么系统的信息要记录在proc中,这是一个文件系统吗?
  • 在/proc目录下面,系统的信息是如何更新的,更新策略是怎样的
  • 如果因为CPU飙升,导致程序崩溃了,重启了,如何去定位问题?当前的各种堆栈信息已经没了,系统都重启,当时问题暂时没办法再现了。
  • 监控告警如何实现,脚本,定时任务,钉钉机器人等等?如果CPU飙升至100%,监控告警还能发送消息吗?
  • 如何去调整某个进程的优先级,让监控报警优先执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值