现象
- 监控中tcp服务全部下线, 查询进程存在
 
- 主机cpu100%, 内存未溢出
 
 分析
- cpu标高, top查看gc进程, 初步确定 Full GC引起
 
- Full GC 说明存在内存溢出问题
 
- 分析内存快照, 发现大量的下行消息堆积(81%), 说明下行阻塞, 可能是网络或者工作线程不足
 
- 其他服务反馈公网超时, 内网很快, 基本确定是网络原因
 
查看prometheus监控, 可以看到线程大量处于 waiting 状态(阻塞), 线程 waiting 导致下行消息堆积,内存增加(监控可见), 触发频繁 gc(监控可见), 频繁 gc 导致cpu load 及 使用率 升高(监控可见)
 cpu飙高线程定位
- 使用top命令查看系统CPU的占用情况
 
1 2 3 4 5 6 7 8 9 10
   | [csy@test-prd18-216 ~]$ top     PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND 1882062 root      20   0 5821124 990.2m  39440 S   3.0   6.3 517:35.57 java 2414864 root      20   0 6705196 928780  43040 S   2.7   5.7  18:31.56 java 2219736 root      20   0 6828528   1.2g  42508 S   2.3   7.7 173:44.09 java   74679 kibana    20   0 1390224 539292  42592 S   1.7   3.3   1746:25 node 2348141 root      20   0 6782016   1.1g  41196 S   1.7   7.0  58:10.43 java 1954780 root      20   0 6714380 946000  42648 S   1.3   5.8 187:26.73 java  286946 root      20   0 6635204 862820  37900 S   0.7   5.3 403:58.62 java 1871394 root      20   0 6706500 926456  35656 S   0.7   5.7 111:34.88 java
   | 
 
- 查看该进程的各个线程运行情况
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | [csy@test-prd18-216 ~]$ top -Hp 1882062 top - 15:06:05 up 77 days,  4:47,  1 user,  load average: 0.40, 0.24, 0.18 Threads: 179 total,   0 running, 179 sleeping,   0 stopped,   0 zombie %Cpu(s):  1.0 us,  0.4 sy,  0.0 ni, 98.2 id,  0.0 wa,  0.4 hi,  0.0 si,  0.0 st MiB Mem :  15830.8 total,    430.5 free,   8943.2 used,   6457.1 buff/cache MiB Swap:      0.0 total,      0.0 free,      0.0 used.   6967.2 avail Mem
      PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND 1882103 root      20   0 5821124 990.2m  39440 S   0.3   6.3  45:55.15 Log4j2-TF-1-Asy 1882145 root      20   0 5821124 990.2m  39440 S   0.3   6.3   0:26.77 es-connection-t 1882175 root      20   0 5821124 990.2m  39440 S   0.3   6.3  20:00.96 MOBILE_CHECK_LI 1882193 root      20   0 5821124 990.2m  39440 S   0.3   6.3  18:55.50 VISITOR_FULL_LI 1882194 root      20   0 5821124 990.2m  39440 S   0.3   6.3   9:22.17 kafka-coordinat 1882083 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:00.00 java 1882063 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:14.28 java 1882064 root      20   0 5821124 990.2m  39440 S   0.0   6.3   3:01.71 GC Thread#0 1882065 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:00.00 G1 Main Marker 1882066 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:00.00 G1 Conc#0 1882067 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:00.02 G1 Refine#0 1882068 root      20   0 5821124 990.2m  39440 S   0.0   6.3   9:01.27 G1 Young RemSet 1882069 root      20   0 5821124 990.2m  39440 S   0.0   6.3   4:18.25 VM Thread 1882070 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:00.01 Reference Handl 1882071 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:00.00 Finalizer 1882072 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:00.00 Signal Dispatch 1882073 root      20   0 5821124 990.2m  39440 S   0.0   6.3   1:29.21 C2 CompilerThre 1882074 root      20   0 5821124 990.2m  39440 S   0.0   6.3   0:16.32 C1 CompilerThre
   | 
 
说明:
1 2 3 4 5 6 7 8
   | us:用户进程空间中未改变过优先级的进程占用CPU百分比 sy:内核空间占用CPU百分比 ni:用户进程空间内改变过优先级的进程占用CPU百分比 id:空闲时间百分比 wa:空闲&等待I/O的时间百分比 hi:硬中断时间百分比 si:软中断时间百分比 st:虚拟化时被其余VM窃取时间百分比
   | 
 
Load高 & CPU高
这是我们最常遇到的一类情况,即load上涨是CPU负载上升导致。根据CPU具体资源分配表现,可分为以下几类:
CPU sys高
这种情况CPU主要开销在于系统内核,可进一步查看上下文切换情况。
如果非自愿上下文切换较多,说明CPU抢占较为激烈,大量进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。
如果自愿上下文切换较多,说明可能存在I/O、内存等系统资源瓶颈,大量进程无法获取所需资源,导致的上下文切换。
CPU si高
这种情况CPU大量消耗在软中断,可进一步查看软中断类型。一般而言,网络I/O或者线程调度引起软中断最为常见:
NET_TX & NET_RX。NET_TX是发送网络数据包的软中断,NET_RX是接收网络数据包的软中断,这两种类型的软中断较高时,系统存在网络I/O瓶颈可能性较大。
SCHED。SCHED为进程调度以及负载均衡引起的中断,这种中断出现较多时,系统存在较多进程切换,一般与非自愿上下文切换高同时出现,可能存在CPU瓶颈。
CPU us高
这种情况说明资源主要消耗在应用进程,可能引发的原因有以下几类:
死循环或代码中存在CPU密集计算。这种情况多核CPU us会同时上涨。
内存问题,导致大量FULLGC,阻塞线程。这种情况一般只有一核CPU us上涨。
资源等待造成线程池满,连带引发CPU上涨。这种情况下,线程池满等异常会同时出现。
Load高 & CPU低
这种情况出现的根本原因在于不可中断睡眠态(TASK_UNINTERRUPTIBLE)进程数较多,即CPU负载不高,但I/O负载较高。可进一步定位是磁盘I/O还是网络I/O导致。
- 线程id都转换成十六进制形式, 即线程快照中的 0x1cb7e3
 
1 2
   | [csy@test-prd18-216 ~]$ printf "%x\n" 1882083 1cb7e3
   | 
 
- 根据进程和线程在线程快照查找原因: nid=0x1cb7e3
 
1
   | jstack 1882062 |grep 1cb7e3
   |