Linux 性能监控与诊断实战

1次阅读

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

Linux 性能监控与诊断实战

top 命令里 %CPU 超过 100 是正常现象吗

是正常的,尤其在多核 CPU 上。top 默认显示的是“所有 CPU 核心累计占用率”,不是单核占比。一个进程跑满 4 核,%CPU 就可能显示 380+。

常见错误现象:%CPU 显示 245 却以为系统出问题;或误判某个进程“吃光 CPU”,其实它只占满两个半核。

  • top1 可切换显示各核心独立负载,更直观判断是否某核被独占
  • 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%,但 awaitr_await/w_await 始终

  • 真正关键指标是 await(平均 I/O 延迟)和 avgqu-sz(平均队列长度),>1 说明请求开始排队
  • iostat -x 1 每秒刷新一次,观察 svctm 已被废弃,不要看;r/sw/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

bpftracetracepoint: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 方法探针,bpftraceret 值需要主动判断正负——脱离上下文看数字,十次有九次会导出错结论。

text=ZqhQzanResources