场景二:服务器变"牛车"------CPU负载飙升
模拟情景:用户反馈系统响应极慢,top 看到 load average 高达 15.0。你需要找出是哪个进程在疯狂消耗CPU,并分析它是否正常。
准备工作
第一步:创建一个CPU 跑满 且会反复自杀重启的坏脚本
进入你的家目录
cd ~
创建脚本,内容是一个死循环,疯狂进行数学运算消耗CPU
cat > bad.sh << 'EOF'
#!/bin/bash
while true
do
echo "I am a bad process, eating CPU..."
纯计算,不写磁盘,避免IO干扰
echo "scale=1000; 4*a(1)" | bc -l 2>/dev/null &
done
EOF
赋予执行权限
chmod +x bad.sh
第二步:配置 Systemd 服务(模拟"自动复活"机制)
sudo tee /etc/systemd/system/bad.service > /dev/null << 'EOF'
Unit
Description=Evil CPU Eater
After=network.target
Service
Type=simple
ExecStart=/bin/bash /root/bad.sh # 注意:如果你不是root用户,请改成 /home/你的用户名/bad.sh
Restart=always
RestartSec=3
Install
WantedBy=multi-user.target
EOF
重载 systemd 并启动这个"恶魔"
sudo systemctl daemon-reload
sudo systemctl start bad
sudo systemctl enable bad # 设置开机自启,增加难度
第三步:再放几个"烟雾弹"进程(模拟正常业务)
用 stress 再压榨两核(如果没有 yum install -y stress 先装一下)
stress --cpu 1 --timeout 600 &
再开一个消耗CPU的 dd 进程
dd if=/dev/zero of=/dev/null &
开始实操
步骤一:实时刷新系统进程列表,按 CPU 占用率从高到低排序显示。
使用top命令,进入交互界面,再按大写C键,使这些进程按照CPU占用率排列。同时再按小写c键,可以让最后一列的COMMAND列显示命令的完整路径。
这个是按下C以及c键后的结果:

这个是仅按下C键后的效果:

目的:找到了占用CPU的进程,获得了他们的PID。
步骤二:拿到了 PID(比如 12345),需要查出这个进程是在哪个目录 启动的,以及它启动时带了什么环境变量。(不会)
Linux 内核会把每个运行中的进程信息,放在 /proc 目录下一个以 数字(PID) 命名的文件夹里。
其中cwd指的是进程的的工作目录;environ保存了其所有环境变量;exe则是其执行程序的绝对路径。

所以:想找到一个进程的启动目录,可以使用
readlink /proc/进程PID/cwd
即可找到该进程的启动目录

接着查看该程序环境变量:
cat /proc/4416/environ | tr '\0' '\n'
这里使用管道符连接 tr 命令,将原本environ文件中不同变量之间的空字符替换成换行符,输出时各个环境变量都能独占一行,更加清晰明了。

步骤三:尝试删除坏进程
在我们启动bad.sh后,出现了很多bc -l 的进程,以及bad.sh本身的进程。尝试使用:
sudo kill -9 PID
的方法删除bc -l 进程,结果发现删除后不一会就又都重新出现了;即使用同样的命令删除bad.sh进程本身,也还是同样的结果:bc进程重新出现,bad.sh本身也换了一个PID 重新在运行。
询问AI后得知,在我们的准备工作中,已将bad.sh注册成了Systemd服务 bad.service,而那些bc -l实际上就是它的子进程。我们在最开始的服务配置中,有一行设置:Restart=always。这代表,当我们用kill杀死这个进程时,Systemd就会马上重启这个进程,导致我们无法删除。

步骤四:不只要杀死进程,还要让它永远不再自动重启。
理解了是Systemd在保护 bad.sh进程,我们就要使用systemctl命令来处理它。使用:
sudo systemctl stop bad
在使用这个命令后,可以发现top中的原本大量存在的bc进程以及bad.sh本身都不见了。
同时我们还要解决其原本设置的开机自启,以防以后对cpu进行恶意占用
sudo systemctl disable bad
小插曲
在刚开始启动bad.sh时,用top命令查看进程,却发现进程中有很多的bc -l 进程,而bad.sh本身其实占的CPU并不多,大概是这样:

而且他们还会动态变化,有些时候甚至看不到bad.sh进程本身。询问AI后得知,这些bc -l是bad的子进程,bad作为父进程,启动了这些子进程,而真正消耗,占据大量CPU的其实是子进程本身。如果遇到都是子进程的情况,可以使用:
pstree -p -s PID
查看该进程的父子关系,这样就可以找出某个垃圾进程的根源,对其进行修改了。
总结
top和systemd服务的使用