进程是程序的运行实例,是资源分配的基本单位。理解进程管理是排查线上问题、优化系统性能的关键技能。每个进程都有唯一的PID,由init进程(PID=1)派生。
fork()
父进程 ──────────────────▶ 子进程
│ │
│ exec() │
│ ┌───────────────┐ │
│ │ 加载新程序代码 │ │
│ └───────┬───────┘ │
│ ▼ ▼
│ ┌─────────┐ ┌─────────┐
│ │ Running │ │ Running │
│ └────┬────┘ └────┬────┘
│ │ │
│ ┌─────┴─────┐ ┌────┴────┐
│ ▼ ▼ ▼ ▼
│ Ready Sleeping Zombie
│ (可运行) (等待I/O) (已终止)
│ │ │
│ ┌────┘ wait()│
│ ▼ ◀─────┘
│ Wake Up 资源回收
│ │
│ ▼
│ Running
│
└── wait()/waitpid() 回收子进程
| 状态 | 代码 | 说明 | 常见场景 |
|---|---|---|---|
| 运行中 | R | 正在CPU上执行或等待调度 | 计算密集型任务 |
| 可中断睡眠 | S | 等待事件(I/O、信号) | 等待网络响应 |
| 不可中断睡眠 | D | 等待不可中断事件 | 等待磁盘I/O |
| 已停止 | T | 被信号暂停 | Ctrl+Z暂停 |
| 僵尸 | Z | 已终止但父进程未回收 | 编程Bug |
信号是进程间通信的基本机制,也是我们管理进程的主要手段:
| 信号 | 编号 | 含义 | 用途 |
|---|---|---|---|
| SIGHUP | 1 | 挂起 | 重载配置(nginx -s reload) |
| SIGINT | 2 | 中断 | Ctrl+C终止前台进程 |
| SIGKILL | 9 | 强制终止 | 无法捕获,最后手段 |
| SIGTERM | 15 | 优雅终止 | kill默认信号,允许清理 |
| SIGSTOP | 19 | 停止 | 无法捕获,暂停进程 |
| SIGUSR1 | 10 | 用户自定义1 | nginx重新打开日志 |
# ps命令 - 静态快照
ps aux # BSD风格,查看所有进程
ps -ef # System V风格
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head
# PID PPID CMD %MEM %CPU
# 1234 1 /usr/bin/python3 12.3 45.2
# 5678 1 /usr/sbin/nginx 2.1 0.5
# top/htop - 动态监控
top -b -n 1 | head -20 # 批处理模式
htop # 交互式(需安装)
# pgrep/pkill - 按名称查找/杀进程
pgrep -af nginx # 查找nginx进程
# 1234 nginx: master process
# 1235 nginx: worker process
pgrep -P 1234 # 查找子进程
pkill -f "python app.py" # 按命令行匹配杀进程
# 启动后台进程
nohup python3 app.py > app.log 2>&1 &
# [1] 12345
# 查看后台任务
jobs -l
# [1]+ 12345 Running nohup python3 app.py &
# 前后台切换
fg %1 # 将后台任务调到前台
Ctrl+Z # 暂停当前前台进程
bg %1 # 将暂停的任务放后台运行
# 发送信号
kill -15 12345 # SIGTERM,优雅终止
kill -9 12345 # SIGKILL,强制终止(最后手段!)
kill -HUP $(pgrep nginx | head -1) # 重载nginx配置
killall -TERM nginx # 按名称终止
# 进程优先级
nice -n 10 ./heavy_task.sh # 低优先级运行
renice -n -5 -p 12345 # 提高优先级(需root)
ps -eo pid,ni,cmd | grep task # 查看nice值
# 创建自定义服务
sudo tee /etc/systemd/system/myapp.service << 'EOF'
[Unit]
Description=My DevOps Application
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=appuser
Group=appgroup
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/start.sh
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/opt/myapp/bin/stop.sh
Restart=on-failure
RestartSec=5s
LimitNOFILE=65536
# 安全加固
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/myapp/data /var/log/myapp
[Install]
WantedBy=multi-user.target
EOF
# 启用并启动
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
# 查看服务状态和日志
sudo systemctl status myapp
sudo journalctl -u myapp -f # 实时日志
sudo journalctl -u myapp --since today
# 查看当前限制
ulimit -a
# core file size (blocks, -c) 0
# open files (-n) 1024
# max user processes (-u) 4096
# 临时修改(当前会话)
ulimit -n 65535 # 增加文件描述符限制
# 永久修改 /etc/security/limits.conf
sudo tee -a /etc/security/limits.conf << 'EOF'
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
root soft nofile 65535
root hard nofile 65535
EOF
# cgroups v2 限制进程资源
sudo systemctl set-property myapp.service MemoryMax=512M
sudo systemctl set-property myapp.service CPUQuota=200%
#!/bin/bash
# 僵尸进程检测与处理
echo "🧟 僵尸进程检测"
echo "================"
# 查找僵尸进程
ZOMBIES=$(ps aux | awk '$8=="Z" {print $2}')
COUNT=$(echo "$ZOMBIES" | grep -c . || echo 0)
if [ "$COUNT" -eq 0 ]; then
echo "✅ 没有僵尸进程"
exit 0
fi
echo "⚠️ 发现 $COUNT 个僵尸进程:"
echo "$ZOMBIES" | while read pid; do
ppid=$(ps -o ppid= -p "$pid" | tr -d ' ')
cmd=$(ps -o comm= -p "$pid")
echo " PID=$pid PPID=$ppid CMD=$cmd"
done
echo ""
echo "修复方案:"
echo "1. 找到父进程,发送SIGCHLD或重启父进程"
echo "2. 如果父进程是init(PID=1),僵尸会自动回收"
echo "3. 最后手段:杀掉父进程(僵尸变为init子进程后回收)"
用户空间
┌────────────────────────────────────────┐
│ App1 App2 App3 Shell Nginx │
└──┬───────┬───────┬──────┬───────┬──────┘
│ │ │ │ │
┌──▼───────▼───────▼──────▼───────▼──────┐
│ 系统调用接口 (syscall) │
└──┬───────────────────────────────────┬──┘
│ │
┌──▼───────────────────────────────────▼──┐
│ 内核空间 │
│ │
│ ┌──────────────────────────────────┐ │
│ │ CFS调度器 (Completely │ │
│ │ Fair Scheduler) │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │CPU 0│ │CPU 1│ │CPU 2│ │ │
│ │ │RunQ │ │RunQ │ │RunQ │ │ │
│ │ └──┬──┘ └──┬──┘ └──┬──┘ │ │
│ └────┼───────┼───────┼───────────┘ │
│ │ │ │ │
│ ┌────▼───────▼───────▼───────────┐ │
│ │ cgroups v2 │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │CPU │ │Memory│ │ I/O │ │ │
│ │ │限制 │ │限制 │ │限制 │ │ │
│ │ └──────┘ └──────┘ └──────┘ │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────────┘
# 识别D状态进程
ps aux | awk '$8 ~ /D/'
# root 4567 0.0 0.1 D 0:00 /usr/bin/storage-sync
# 查看等待的内核栈
cat /proc/4567/stack
# [] io_schedule+0x12/0x40
# [] wait_on_page_bit+0x82/0xa0
# 常见原因:NFS挂载超时、磁盘故障、iSCSI断连
# 解决:修复底层存储问题,无法kill -9 D状态进程
# 如果是NFS导致的D状态
umount -f /mnt/nfs # 强制卸载
# 或:设置NFS超时参数
mount -t nfs -o hard,intr,timeo=10 server:/share /mnt/nfs
# 查看OOM记录
dmesg | grep -i "oom-killer" | tail -5
journalctl -k | grep -i oom
# 查看OOM评分
cat /proc/$(pgrep myapp)/oom_score
cat /proc/$(pgrep myapp)/oom_score_adj
# 防止关键进程被OOM杀掉
echo -1000 | sudo tee /proc/$(pgrep myapp)/oom_score_adj
# 或在systemd服务中配置
# OOMScoreAdjust=-1000
# 根本解决:增加内存或限制进程内存使用
sudo systemctl set-property myapp.service MemoryMax=1G
掌握进程生命周期、信号机制、systemd服务管理、cgroups资源限制——这是排障和性能优化的核心技能。