进程与性能排查实战:从 ps/top 到负载分析

“服务器变慢了”是运维收到最多的反馈,但它背后可能是 CPU、内存、磁盘 IO、网络任意一环的问题。这篇把排查思路和工具串成一条完整的链路,遇到问题按顺序走,很少会抓瞎。

一、排查思路:先定位资源,再定位进程

标准四问:

  1. 谁在吃 CPU?→ top / ps aux --sort=-%cpu
  2. 谁在吃内存?→ free -h / top / ps aux --sort=-%mem
  3. 谁在等 IO?→ top(看 D 状态)/ iostat
  4. 谁在占端口/文件?→ lsof / ss

二、ps:进程快照

1
2
3
4
5
ps aux                          # 完整信息(%CPU %MEM STAT)
ps -ef # 完整格式(含 PPID、启动时间)
ps aux --sort=-%cpu | head -20 # 按 CPU 排序
ps aux --sort=-%mem | head -20 # 按内存排序
ps -ef --forest | grep -A5 nginx # 进程树,看父子关系

STAT 列是重点——它直接告诉你进程卡在哪:

状态 含义 排查提示
R 运行/排队等 CPU 结合 %CPU 看是否异常
S 睡眠等事件 正常
D 不可中断的磁盘等待 磁盘有问题(NFS 挂、磁盘故障),kill 不掉
Z 僵尸进程 父进程没 wait() 收尸,找父进程处理
T 被暂停 如 Ctrl+Z

三、top:动态监控

1
2
3
4
top
# 交互键:P 按CPU排序 M 按内存 T 按时间 1 展开每核 c 完整命令 H 看线程
top -u www-data # 只看某用户的进程
top -Hp 1234 # 看线程级(排查 Java 线程吃 CPU 必备)

负载的判读:load average: 12.50, 8.30, 4.20 是 1/5/15 分钟平均负载。负载要和 CPU 核数对比

1
2
nproc   # 查看核数
# 以 4 核为例:负载 <4 正常;=4 跑满;>4 有排队;>8 严重过载立即查

CPU 各列关注 wa(iowait)和 si(软中断):wa > 20% 立刻查磁盘 IO(iostat);si 高说明网络流量大,查网卡和连接数。

内存看 free -h,重点盯 si/so(swap 换入换出):vmstat 1 如果 si/so 持续非零,说明内存吃紧在疯狂换页,要扩容或优化应用。

四、lsof:谁占用了什么

1
2
3
4
lsof -i :80          # 谁在监听 80 端口
lsof -p 1234 # 某进程打开了哪些文件
lsof | grep deleted # 查"文件删了但空间没释放"的元凶
lsof +D /data # 谁占用了某目录(umount 报 busy 时用)

经典场景:rm 了大日志但 df -h 空间没变——进程还持有文件句柄,文件没真正释放。解决:重启进程,或 > /proc/进程PID/fd/句柄号 清空。

五、一次 Java 线程高 CPU 排查实录

现象:业务反馈接口 P99 飙升,top 看到 java 进程 CPU 400%(占满 4 核)。

排查链路:

  1. top -Hp 1234 找到最耗 CPU 的线程 PID(比如 3039);
  2. 转十六进制:printf "%x\n" 3039bdf
  3. jstack 1234 | grep -A20 'nid=0xbdf' → 定位到具体业务线程和代码行;
  4. 发现是某个批量任务循环里不断创建连接未释放,上线前压测没覆盖到;修复后二次压测,CPU 回到 20% 以内。

六、工具补充记忆点

  • pidstat -u 2 5:每 2 秒采样 5 次看进程 CPU;-d 看 IO;-w 看上下文切换(自愿切换多=在等锁/IO,非自愿多=CPU 竞争激烈)
  • pmap -x <pid>:进程内存分布
  • /proc/cpuinfo/proc/meminfo/proc/loadavg/proc/<pid>/cmdline:最底层数据来源,没有工具时直接读这里

排查性能问题没有银弹,但固定这套”先资源、后进程、再线程”的顺序,大部分问题都能在半小时内定位到根因。