1 先查看有无错误日志(回滚)、上下游调用是否正常(通知、降级、熔断)
2 若是单台飙升则重启机器或置换
3 若全部都飙升则说明程序里有线程一直长时间占用CPU则先摘流一台保留现场用来后续分析问题,其它重启快速恢复服务
4 top 查看机器进程占用 CPU 最高进程号 (此时可以通过 jinfo pid 了解服务信息), top -Hp pid 找到 CPU 占比最大的线程
5 将线程号转换为十六进制 $printf “%xn” 4858 12fa (线程栈里是十六进制)
6 jstack pid | grep -A 10 [线程 16 进制] 明确 CPU 负载如此高的线程到底在干什么 比如是 GC 线程(GC 异常频繁)
7 找寻为何 GC 如此频繁原因:jstat -gc、gcutil、class 查看堆空间、大对象情况
8 jmap -dump 生成快照文件分析(zip 压缩、摘除流量再执行)
9 发现 JceSecurity 对象占据了 90%的堆空间
10 通过可视化工具继续查看此对象各属性,发现其中有个 Map 属性 Map<Provider, Object> verificationResults 量级巨多
11 verificationResults 的 v 类型是 BouncyCastleProvider 从代码里找这个类的应用处
12 发现是在一个方法里每次调用都会生成一个对象塞入 Map,将这个对象变成 static,每次调用不要创建对象而是复用这个类对象
以上是很常见的 CPU 飙高的场景,表面是 CPU 不足,其实是因为 FullGC 长期运行大量占用 CPU 的结果
历史经验1 YongGC 线程导致
业务代码导致的内存泄露 or 溢出修复
创建大量对象但一直被引用(数据库获取大量数据追加到 List、方法调用每次都 new 对象放入对象级别 Map 属性)
创建大对象(超大 String 对象,逻辑内不断改写 直接放入老年代)
资源用完未主动回收(Socket、Stream)
每次运行加解密都会 new 一个 BouncyCastleProvider 对象,放倒 Cipher.getInstance()方法中
每次运行到加解密都会向这个 map put 一个对象,而这个 map 属于类的维度,所以不会被 GC 回收。这就导致了大量的 new 的对象不被回收
2 业务线程导致业务代码有死锁或死循环导致 CPU 长期占用(除非时间片到了否则不会主动让出 CPU)
另外如果程序中有序列化反序列化、正则表达式匹配逻辑,也有因数据处理耗时过大导致 CPU 飙高的风险