Linux 进程管理与性能排查实战:从 top、strace 到 perf 的完整决策链 原创
为什么进程排查是运维的底层能力
监控系统告诉你”机器有问题”,但定位到”哪个进程、哪段代码、哪个系统调用”靠的是进程级工具链。CPU 飙高、内存泄漏、负载虚高、进程 D 状态卡死,这四类问题的排查路径完全不同。本文把 ps、top、strace、perf、vmstat 串成一条可复用的决策链路,而不是孤立地背命令参数。
第一步:先判断瓶颈类型,再选工具
不要一上来就敲 top。先用负载与等待队列区分”真忙”和”卡死”:
uptime
# load average: 8.00 7.2 6.5 —— 负载高不等于 CPU 忙
vmstat 1 5
# 看 r(运行队列)、b(不可中断等待)、wa(IO 等待)、us/sy(用户/内核态)
| 现象组合 | 瓶颈 | 首选工具 |
|---|---|---|
| r 大、us 高、wa 低 | CPU 计算密集 | top/perf |
| b 大、wa 高 | 磁盘 IO 等待 | iostat/iotop |
| sy 高、r 不大 | 系统调用/上下文切换频繁 | strace/perf |
| load 高但 CPU 空闲 | 大量 D 状态进程(等 IO/锁) | ps + /proc/pid/stack |
关键认知:load average 统计的是”正在运行 + 不可中断睡眠”的进程数。NFS 卡死、磁盘 hang 住时,进程全部进入 D 状态,负载能堆到几十,但 CPU 使用率是 0。只看 CPU 会完全误诊。
第二步:ps 与 top 定位到具体进程
ps 适合快照与脚本,top 适合持续观察。几个真正高频的组合:
# CPU 占用排序,看完整命令行
ps -eo pid,ppid,%cpu,%mem,stat,etime,cmd --sort=-%cpu | head -20
# stat 列是精髓:R 运行 / S 睡眠 / D 不可中断 / Z 僵尸 / + 前台 / 多线程 l
ps -eo pid,stat,wchan:30,cmd | awk '$2 ~ /D/'
在 top 里:按 P 按 CPU 排序、M 按内存排序、H 切换线程视图、1 展开每个 CPU 核心。线程视图对定位 Java、Node、worldserver 这类多线程进程至关重要——进程总 CPU 200% 时,必须下钻到是哪条线程在烧。
# 找到高 CPU 的线程 TID 后
top -H -p <pid>
# 把 TID 转成十六进制,再到 jstack / gdb 里对照线程栈
printf '%x\n' <tid>
第三步:strace 看进程在”求内核做什么”
当进程表现异常(卡住、狂打日志、响应慢)但源码不在手上时,strace 直接展示它与内核的边界——每一次系统调用。
# 附着到运行中的进程,统计系统调用耗时
strace -f -p <pid> -c
# -c 汇总:哪类调用次数最多、耗时最长
# 追踪网络与文件相关调用,并打印时间戳
strace -f -p <pid> -tt -e trace=openat,read,write,connect,recvfrom,sendto 2>&1 | head -100
典型用法:进程”假死”时 attach 上去,若反复看到 futex(..., FUTEX_WAIT),说明在等一把用户态锁(死锁或锁竞争);若卡在某个 read() 指向的 fd,用 ls -l /proc/<pid>/fd/<n> 就能查出它到底在等哪个文件或 socket。生产环境慎用:strace 有可观的 ptrace 开销,排查结束立即 detach。
第四步:perf 从进程下钻到函数
strace 只到系统调用层,CPU 真正耗在用户态哪个函数,要用 perf。
# 采样整个系统 30 秒,生成火焰图原料
perf record -F 99 -a -g -- sleep 30
perf script | stackcollapse-perf.pl | flamegraph.pl > cpu.svg
# 只看单个进程,并直接看 top 函数
perf top -p <pid>
火焰图读法:横轴是采样命中比例(不是时间流逝),纵轴是调用栈。一个”宽平台”就是热点函数。相比盲目猜测,perf 用统计采样给出证据,且开销量化可控。权限不足时需要 kernel.perf_event_paranoid 调整或 root。
内存问题:区分 RSS、缓存与泄漏
内存”被占满”在 Linux 上多半是假象——free 的 buff/cache 是可回收的。真正要盯的是进程的常驻物理内存。
# 按实际内存排序,RSS 单位 KB
ps -eo pid,%mem,rss,cmd --sort=-rss | head
# 持续观察某进程 RSS 是否单调增长(泄漏特征)
watch -n 5 'ps -o rss= -p <pid>'
# 更细:按进程看内存分布
cat /proc/<pid>/status | grep -E 'VmRSS|VmSwap|Threads'
pmap -x <pid> | sort -k3 -n | tail
判断泄漏的标准不是”占用高”,而是”流量回落之后 RSS 不回落、且持续单调上升”。若 VmSwap 持续增长,说明物理内存不足触发了换出,这比 OOM 更早出现,应该在此阶段扩容或限流,而不是等 OOM Killer 动手。
一条可复用的排查决策链
1. uptime / vmstat 1 → 判定 CPU / IO / 锁 哪类瓶颈
2. ps --sort + top -H → 定位到进程与线程
3. strace -c / -e → 看系统调用与锁等待
4. perf record / top → 下钻到用户态热点函数
5. /proc/pid/status → 核对内存与线程数,留存证据
工具的价值不在参数记得多,而在顺序正确:先分型、再定位、后下钻、留证据。每一步都用证据排除一类原因,最终收敛到根因,而不是在 top 界面里凭直觉乱猜。