多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

CPU 飙到 100%,先别急着翻代码

CPU 飙到 100%,先别急着翻代码 CPU 飙到 100%先别急着翻代码Java 线上排查的四步法与三个坑经典排查流程整理与修订 · 作者观点仅供讨论线上告警某台机器 CPU 打满。很多人的第一反应是翻代码、猜哪里有死循环。我的观点是**先定位再推理最后才看代码。**CPU 高只是症状背后可能是业务线程在空转也可能是 GC 在疯狂回收两者的处理方向完全不同。下面先给一套四步法进程 → 线程 → 十六进制 → 栈再讲我认为最容易踩的三个坑最后是工具选择和线上现实。01第一步找到“最忙”的进程用top按 CPU 排序找到占用最高的进程 PID如果机器上有多个 Java 进程再用jps -l或ps -ef确认它是哪个应用。top jps -l ps -ef | grep java | grep -v grep假设找到的进程 PID 是 5101。02第二步找到“最忙”的线程进程是容器真正吃 CPU 的是线程。有两种做法# 方式一直接看线程级 CPU更直观 top -Hp 5101 # 方式二列出该进程的所有线程及其 CPU 时间 ps -mp 5101 -o THREAD,tid,time参数含义-m显示进程下的所有线程-p指定进程 ID-o自定义输出列这里是线程信息、线程 ID 和累计 CPU 时间。假设最忙的线程 TID 是 5102。03第三步线程 ID 转十六进制jstack 输出里的线程号nid是十六进制而top和ps给的是十进制必须转换printf %x\n 5102 # 输出13ee04第四步用 jstack 找到具体代码jstack 5101 | grep -A 30 nid0x13ee输出里就能看到该线程的名字、状态和调用栈沿着栈顶往下找到你们自己的业务类和行号问题代码基本就定位出来了。05坑一把 GC 问题当成业务代码问题如果第四步看到的线程名是GC task thread、VM Thread或G1 Concurrent开头说明 CPU 是被垃圾回收吃掉的翻业务代码是找不到答案的。做法用jstat -gcutil 5101 1000 10观察各区使用率和 GC 次数、耗时老年代长期居高、Full GC 频繁就转向内存泄漏或堆配置问题再用jmap -histo查对象分布。判断CPU 高要先问是业务线程在忙还是 GC 在忙这一步分岔决定后面全部的方向。06坑二只抓一次快照一次 jstack 只是某一瞬间的画面。如果线程刚好在做正常的计算你会误判真正的死循环或热点则会在多次快照里停在同一处。做法间隔几秒抓 3 次比较同一个 TID 的栈。始终停在同一行附近基本就是死循环或热点代码栈每次都在变更可能是整体负载过高该考虑限流、扩容或优化算法。07坑三随手在生产上跑 jmap原文列了一串常用工具jps看进程jstat看统计jmap看内存映像jinfo看配置。罗列没问题但要补一条风险提醒jmap -dump会让应用明显停顿jmap -histo:live会触发一次 Full GC高峰期在线上直接执行可能把本来不严重的问题变成事故。症状优先工具注意CPU 高疑似业务死循环top -Hpjstack连抓多次对比CPU 高疑似 GCjstat -gcutil先看 GC 趋势再动手内存持续上涨、疑似泄漏jmap -histo、堆转储分析转储会停顿错峰或在摘流量的实例上做确认启动参数是否生效jinfo只读风险低找 Java 进程jps -l容器内需有 JDK 工具08线上现实手工四步要会但别只会手工在容器和 K8s 环境里会遇到几个实际问题容器镜像里可能只有 JRE没有 jstackJava 进程的 PID 常常是 1执行用户要和 Java 进程一致否则会没有权限。取理解四步法背后的原理这样才看得懂任何排查工具在干什么遇到没有工具的环境也能手工兜底。舍线上优先用更成熟的工具比如 Arthas 的thread -n 3一条命令就能列出最忙的几个线程和栈或者用 async-profiler 做采样分析。更重要的是把工具提前放进镜像或运维平台出事时才不用现装。总结CPU 飙高的排查核心是一个顺序先分清谁在忙业务线程还是 GC再用进程、线程、十六进制、栈四步缩小范围多抓几次快照确认最后才回到代码。排查完别忘了做两件事把这次的过程写成 SOP把对应指标加上监控告警让下一次不再靠人在深夜手工敲命令。说明命令示例基于常见 Linux 与 JDK 环境输出格式与参数可能因系统和版本不同而略有差异。
返回列表