真高负载需同时满足uptime显示load average持续高于核心数且mpstat中%iowait很低(20%,实为磁盘I/O瓶颈,非CPU问题。

怎么一眼判断是真高负载还是假报警
别急着杀进程——先看 uptime 和 mpstat -P ALL 1。如果 load average 持续高于 nproc 输出的核心数,且 %iowait 很低(%usr 占主导(>70%),那才是真实计算型过载;如果 %iowait 长期 >20%,其实是磁盘慢导致 CPU 空等,这时压根不是 CPU 问题,强行限 CPU 只会让响应更卡。
Java 进程 CPU 飙高:jstack + top -H 的标准联动操作
Java 应用占满一个核最常见,但错误做法是直接 kill -9。正确路径是:先 top -H -p [PID] 找出高耗线程 TID,再用 printf "%x\n" [TID] 转成小写十六进制,最后在 jstack [PID] 输出里搜这个值。重点看栈顶是不是 java.util.HashMap.get(哈希碰撞风暴)、Pattern.matcher(正则回溯)、或无限 while(true) + Thread.sleep(1)(伪休眠实轮询)。
perf 火焰图不等于“高级=有用”,得会读关键宽度
跑 sudo perf record -p [PID] -g -- sleep 20 后生成火焰图,别被满屏函数吓住。真正要盯的是横向最宽的几条“山峰”:如果宽条全在 libc 或 pthread_mutex_lock,说明锁竞争;如果集中在某个业务类的 computeXXX 方法,就是算法复杂度爆炸;如果大量 __kernel_vsyscall 堆在底部,大概率是频繁系统调用(比如每毫秒 gettimeofday())。火焰图宽 ≠ 耗时长,而是调用频次高 —— 这点很多人误读。
临时控不住?cpulimit 是双刃剑
cpulimit -p [PID] -l 30 看似立竿见影,但 Java 应用可能因 GC 线程被掐断而触发 Full GC 雪崩,Python 的 GIL 调度也可能紊乱。更稳妥的应急是 cgroup 限核:cgcreate -g cpu:/lowcpu && echo [PID] > /sys/fs/cgroup/cpu/lowcpu/cgroup.procs && echo 50000 > /sys/fs/cgroup/cpu/lowcpu/cpu.cfs_quota_us(限制为 0.5 核)。它不中断线程,只节流调度配额,对 JVM 更友好。
真正难的不是定位,而是区分“单次毛刺”和“稳态过载”:前者可能是 cron 任务叠加,后者往往藏在日志里反复出现的 WARN 级重试、或监控中缓慢爬升的线程数。别跳过 ps -eo pid,%cpu,etime,cmd --sort=-%cpu | head -10 里的 etime(运行秒数)—— 如果一个 95% CPU 的进程已跑了 7200 秒,基本可以排除瞬时抖动了。








