← 回目录
11 Week 03 · 服务和进程

进程:谁在跑,谁在吃 CPU

第三周开始。「服务器变慢了」是运维最常接到的报障,而排查它的第一站,就是今天这几个命令。

今天要敲的
$ ps aux | head
$ ps aux | grep sshd
$ top                      # q 退出,M 按内存排,P 按 CPU 排
$ uptime                   # 看负载
$ kill 1234                # 温和地停
$ kill -9 1234             # 强杀,最后手段

ps aux

当前所有进程的快照
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
USER
这个进程以谁的身份在跑。Day 07 排查 403 时就是看它——nginx 到底是哪个用户。
PID
进程号。要杀进程就得先拿到它。
%CPU / %MEM
占用的 CPU 和内存百分比。
RSS
实际占用的物理内存(KB)。比 VSZ 更有参考价值——VSZ 是虚拟地址空间,通常大得吓人但没意义。
STAT
进程状态。R 运行中、S 睡眠等待、D 不可中断(通常是在等磁盘 IO)、Z 僵尸。
COMMAND
启动它的完整命令行。
STAT 里的 D 值得警惕

大量进程卡在 D 状态,说明它们都在等磁盘——这通常意味着磁盘性能到瓶颈了,而不是 CPU 不够。

「系统很卡但 CPU 不高」,多半就是这种情况。

最常用的三个组合
$ ps aux | grep nginx              # 找某个服务的进程
$ ps aux --sort=-%cpu | head -5    # CPU 占用前 5
$ ps aux --sort=-%mem | head -5    # 内存占用前 5

top

实时的动态视图

ps 是快照,top 是实时刷新。「服务器变慢了」第一个敲的就是它。

top 的头几行才是重点
top - 15:22:01 up 3 days,  2:14,  2 users,  load average: 0.52, 0.48, 0.41
Tasks: 178 total,   1 running, 177 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.3 us,  0.7 sy,  0.0 ni, 96.8 id,  0.2 wa,  0.0 hi
MiB Mem :   3823.4 total,    412.8 free,   1204.6 used,   2206.0 buff/cache
这几个数字要会读
load average
最近 1 / 5 / 15 分钟的平均负载。拿它跟 CPU 核数比:4 核机器负载 4 以内算正常,长期超过核数就是过载。
三个数还能看趋势:前面大后面小 = 正在恶化;前面小后面大 = 正在恢复。
%Cpu id
空闲百分比。看这个比看 us 直观——id 接近 0 就是 CPU 打满了。
%Cpu wa
等待 IO 的时间占比。这个高说明瓶颈在磁盘不在 CPU。
buff/cache
被系统拿去做缓存的内存。它不算真正被占用——需要时会自动释放,别看到 free 少就慌。
在 top 里按这几个键

P 按 CPU 排序、M 按内存排序、1 展开每个 CPU 核心、k 直接杀进程、q 退出。

进去先按 M——内存问题比 CPU 问题更常见,而且后果更严重(会触发 OOM 杀进程)。

kill

别一上来就 -9
两个信号的本质区别
kill(默认 -15 TERM)
发一个「请你退出」的信号。程序能收到、能处理——保存数据、关闭连接、删除锁文件,然后自己退出。优先用这个。
kill -9(KILL)
内核直接干掉,程序收不到任何通知,没机会做任何清理。可能留下损坏的数据、残留的 PID 文件或锁。
正确的顺序
$ ps aux | grep myapp          # 1. 找到 PID
$ kill 3021                    # 2. 先温和地停
$ ps aux | grep myapp          # 3. 等几秒,确认没了
$ kill -9 3021                 # 4. 还在才用 -9

# 按名字杀,不用先找 PID
$ pkill nginx
$ pkill -f "python myapp.py"   # -f 匹配完整命令行
杀服务其实不该用 kill

如果是 systemd 管理的服务(明天讲),正确做法是 systemctl stop nginx,而不是 kill

直接 kill 掉,systemd 可能因为配置了自动重启又把它拉起来,或者状态记录变得不一致。kill 主要用在那些不受 systemd 管的进程上。

顺带认识僵尸进程

面试偶尔会问

STATZ 的进程叫僵尸进程。它已经死了,但父进程还没来收尸(没读取它的退出状态),所以在进程表里占着一个位置。

怎么处理
$ ps aux | grep defunct        # 找僵尸进程

# 僵尸进程本身杀不掉(它已经死了)
# 要杀的是它的父进程,父进程一死,僵尸会被 init 接管并清理
$ ps -o ppid= -p <僵尸的PID>    # 查它爹是谁

少量僵尸进程没有危害(不占 CPU 不占内存),只有大量堆积才需要处理。知道这点就够了,别被面试官问倒说「僵尸进程要赶紧杀」。

今天的面试点

「kill 和 kill -9 有什么区别?」

kill 发的是 TERM 信号,程序能捕获、能优雅退出,可以保存数据、清理资源;-9 是 KILL 信号,内核直接干掉,程序没机会清理,可能留下损坏数据或残留锁文件。」

我一般先试普通 kill,等几秒确认没退再用 -9。

「服务器变慢了,你怎么查?」

「先 topload average 跟 CPU 核数比,再看 %Cpu 那行——如果 id 很低就是 CPU 打满了,如果 wa 高说明瓶颈在磁盘 IO。然后按 M 看内存占用排名。」

加分:「如果 CPU 不高但系统很卡,我会看有没有大量进程卡在 D 状态——那是在等磁盘。」

今天的练习

敲完再走 · 约 12 分钟
  • ps aux | head,对着上面的表把每一列认一遍
  • ps aux --sort=-%mem | head -5,看看你这台虚拟机什么最吃内存
  • uptime 看负载,再 nproc 看几核,用负载除以核数判断忙不忙
  • top,依次按 MP1,最后 q 退出
  • 实验杀进程:开个 sleep 300 & 放后台,ps aux | grep sleep 找到 PID,先用 kill 停掉,确认没了
  • 再来一次,这回用 pkill sleep 按名字杀
明天预告

Day 12 讲 systemctl——RHEL 7 之后管服务的唯一正确方式,也是你那台 RHEL 7 过时的原因之一。老教程里的 service xxx start 该忘掉了。