是正常的,%cpu超100表示多核累计占用率,如4核满载可达380+;%util高但await低说明i/o并发能力强,并非必然瓶颈;perf需jvm加-xx:+preserveframepointer才可解析java栈;bpftrace捕获open失败须过滤负返回值并转错误名。

top 命令里 %CPU 超过 100 是正常现象吗
是正常的,尤其在多核 CPU 上。top 默认显示的是“所有 CPU 核心累计占用率”,不是单核占比。一个进程跑满 4 核,%CPU 就可能显示 380+。
常见错误现象:%CPU 显示 245 却以为系统出问题;或误判某个进程“吃光 CPU”,其实它只占满两个半核。
- 用
top按1可切换显示各核心独立负载,更直观判断是否某核被独占 -
htop默认就分核显示,且支持鼠标和颜色,比top更适合快速定位热点核心 - 如果想看单个进程的真实 CPU 使用率(归一化到 100%),用
ps -o pid,ppid,%cpu,comm -C <code>your_cmd,它的%cpu是按总逻辑 CPU 数折算的
为什么 iostat -x 看到 %util 接近 100 但响应并不慢
%util 表示设备忙于处理 I/O 请求的时间百分比,并不直接等于“瓶颈”。SSD、NVMe 或带缓存的 RAID 卡能在高 %util 下维持低延迟,因为它们并发能力强、队列深。
使用场景:线上数据库服务器磁盘 %util 长期 95%,但 await 和 r_await/w_await 始终
- 真正关键指标是
await(平均 I/O 延迟)和avgqu-sz(平均队列长度),>1 说明请求开始排队 -
iostat -x 1每秒刷新一次,观察svctm已被废弃,不要看;r/s和w/s结合rkB/s/wkB/s才能看出是小包还是大块读写 - 如果
%util高但await低,优先检查是不是压测工具或备份任务在持续发 I/O,而非硬件故障
perf record 抓不到 Java 应用的函数调用栈
默认情况下,perf 只能采集内核态和未加壳的用户态符号,Java 的 JIT 编译代码在运行时生成,没有固定符号表,perf 无法自动解析方法名。
容易踩的坑:直接跑 perf record -p <code>pid 后用 perf report,看到一堆 [unknown] 或 __libc_start_main,误以为采样失败。
- 必须启用 Java 的
-XX:+PreserveFramePointer启动参数,让 JVM 保留帧指针,perf才能做栈回溯 - 配合
perf script -F comm,pid,tid,cpu,time,period,sym导出原始数据,再用jdk/bin/jstack <code>pid对齐线程状态 - 生产环境慎用
perf record -g(带调用图),开销比 flat 模式高 3–5 倍,可能加剧 GC 压力
用 bpftrace 查容器内进程的 open() 失败原因总是漏掉 ENOENT
bpftrace 的 tracepoint:syscalls:sys_enter_openat 能捕获所有 open 尝试,但 sys_exit_openat 返回值需手动提取,而 ENOENT(-2)这类错误码只有在返回负值时才有效——很多人只打印了 args->ret 却没过滤负数。
性能影响:每秒几万次 open 尝试下,无条件打印会迅速打爆终端或日志文件,建议用聚合计数代替逐条输出。
- 正确做法是用
syscall:sys_exit_openat / args->ret ret)] = count(); },配合内置err_str()函数转错误名 - 容器场景要加
if (pid == $1)或匹配comm,否则会混入宿主机其他进程的系统调用 - 注意
openat是实际系统调用,open在 libc 中会被转成openat(AT_FDCWD, ...),所以只监听openat就够了
%util 不是利用率,%CPU 不是核心数上限,perf 不是 Java 方法探针,bpftrace 的 ret 值需要主动判断正负——脱离上下文看数字,十次有九次会导出错结论。









