最近在 CentOS 7 生产环境中遇到一次 Linux 系统 PID 耗尽的问题。当时系统无法创建新进程,SSH 登录失败,服务启动异常。本文详细记录从发现问题到最终解决的完整过程,希望能帮到遇到类似问题的朋友。
1. 问题现象与根本原因#
问题现象#
- SSH 无法登录,提示资源不可用
- 系统服务启动失败
- 执行命令报错 “Resource temporarily unavailable”
根本原因#
- CentOS 7 内核(3.10) 的 PID 分配机制有限制,在高频率创建/销毁进程的场景下容易耗尽
- 系统默认的 pid_max 值为 32768,对于长期运行的服务器或进程密集型应用来说偏低
- 本次案例的罪魁祸首是 MobaXterm 的资源监控功能,会在后台不断创建
bash -c while true 循环进程
2. 排查步骤#
步骤 1:确认 PID 使用情况#
首先确认是否真的出现了 PID 耗尽问题:
1
2
3
4
5
6
7
| # 查看系统最大 PID 限制值(默认通常是 32768)
cat /proc/sys/kernel/pid_max
32768
# 查看当前正在使用的 PID 数量
ls /proc/[0-9]* 2>/dev/null | wc -l
32765
|
如果发现已用 PID 接近或达到 pid_max 值,就可以确认是 PID 耗尽问题。
步骤 2:定位 PID 快速增长的元凶#
找出哪些进程在大量占用 PID:
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 方法 1:通过 top 查看进程数量排名(取前 50 行)
top -c -b -n 1 | head -50
# 方法 2:统计各进程出现次数,找出异常进程
ps -eo pid,ppid,comm --no-headers | awk '{print $3}' | sort | uniq -c | sort -rn | head -20
# 输出示例:
# 15234 bash
# 8200 sshd
# 5234 while
# 方法 3:实时监控 PID 数量变化(每秒刷新)
watch -n 1 'ps -e --no-headers | wc -l'
|
在我的案例中,发现 bash 进程数量异常多,进一步排查发现大量 bash -c while true 进程。
步骤 3:排查进程来源#
找到异常进程后,需要确定它们是如何被启动的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # ========== 检查定时任务 ==========
crontab -l # 查看当前用户的定时任务
crontab -l -u root # 查看 root 用户的定时任务
cat /etc/crontab # 查看系统级 crontab
ls -la /etc/cron.d/ # 查看额外的 cron 配置
ls -la /etc/cron.hourly/ # 每小时执行的任务
ls -la /etc/cron.daily/ # 每天执行的任务
# 查看 cron 日志(CentOS 7 通常在 /var/log/cron)
tail -n 100 /var/log/cron | grep -i error
# ========== 检查登录自动启动脚本 ==========
cat /etc/profile
cat /etc/bashrc
cat ~/.bashrc
cat ~/.bash_profile
cat ~/.profile
# ========== 检查系统服务启动项 ==========
systemctl list-unit-files --type=service | grep enabled
# 检查特定服务的 PID 使用情况
systemctl status <service_name>
|
通过排查,最终发现这些 while true 循环进程是由 MobaXterm 的资源监控功能 触发的。每当通过 MobaXterm 连接到服务器时,它会自动在后台启动资源监控脚本,而这些脚本没有正确退出,导致进程累积。
步骤 4:检查系统资源整体情况#
顺便检查其他资源是否也接近上限:
1
2
3
4
5
6
7
8
9
10
11
12
| # 检查 inode 使用率
df -i
# 查看系统总打开文件数
lsof | wc -l
# 查看各进程文件描述符使用情况(取前 20)
ls /proc/[0-9]*/fd 2>/dev/null | xargs -I {} sh -c 'echo {}: $(ls {} 2>/dev/null | wc -l)' | sort -t: -k2 -nr | head -20
# 查看文件描述符系统限制
cat /proc/sys/fs/file-max
cat /proc/sys/fs/nr_open
|
3. 解决方案#
方案一:立即止损(临时方案)#
如果系统已经因为 PID 耗尽而无法操作,先通过现有连接执行以下命令:
1
2
3
4
5
6
7
8
9
10
11
| # 1. 立即终止所有异常循环进程
pkill -f "while true"
# 如果上述命令无法执行,尝试强制终止
ps aux | grep "while true" | grep -v grep | awk '{print $2}' | xargs kill -9 2>/dev/null
# 2. 临时提高 PID 上限(立即生效,但重启后失效)
echo 4194304 > /proc/sys/kernel/pid_max
# 3. 验证当前 PID 使用是否下降
ls /proc/[0-9]* 2>/dev/null | wc -l
|
方案二:永久解决(推荐)#
修改内核参数,永久提高 PID 上限:
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 编辑 sysctl 配置文件
sudo vi /etc/sysctl.conf
# 在文件末尾添加或修改以下配置
# 64 位系统建议设为 4194304(2^22),这是现代系统的安全上限
kernel.pid_max = 4194304
# 使配置立即生效
sudo sysctl -p
# 验证修改结果
cat /proc/sys/kernel/pid_max
# 输出:4194304
|
CentOS 7 注意:
- 4194304 是 64 位系统的理论上限,实际使用时不会有性能影响
- 修改后无需重启系统,立即生效
方案三:从源头解决 MobaXterm 问题#
既然定位到是 MobaXterm 导致的问题,需要在使用端进行修复:
关闭 MobaXterm 资源监控功能
- 打开 MobaXterm → Settings → Configuration → Terminal
- 取消勾选 “Monitor remote server resources”
清理已连接的会话中的残留脚本
- 如果之前开启了资源监控,可能需要在每个服务器上手动清理残留的监控脚本
检查并删除可能残留的启动脚本
1
2
3
4
5
| # 检查用户目录下是否有 MobaXterm 相关的脚本
find ~ -name "*mobaxterm*" -o -name "*resource*monitor*" 2>/dev/null
# 检查 /tmp 目录
ls -la /tmp/ | grep -i moba
|
4. 监控与预防#
设置监控告警#
建议设置定时任务监控 PID 使用情况:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # 创建监控脚本
sudo tee /usr/local/bin/check_pid_usage.sh << 'EOF'
#!/bin/bash
PID_MAX=$(cat /proc/sys/kernel/pid_max)
PID_USED=$(ls /proc/[0-9]* 2>/dev/null | wc -l)
PID_PERCENT=$((PID_USED * 100 / PID_MAX))
if [ $PID_PERCENT -gt 80 ]; then
echo "[WARNING] PID usage is at ${PID_PERCENT}% (${PID_USED}/${PID_MAX})" | \
logger -t pid_monitor
# 可以在这里添加发送邮件或告警的脚本
fi
EOF
sudo chmod +x /usr/local/bin/check_pid_usage.sh
# 添加到 crontab,每 5 分钟检查一次
echo "*/5 * * * * root /usr/local/bin/check_pid_usage.sh" | sudo tee -a /etc/crontab
|
推荐配置#
对于 CentOS 7 生产服务器,建议进行以下配置:
1
2
3
4
5
6
7
8
9
10
11
| # 添加到 /etc/sysctl.conf
# 提高 PID 上限
kernel.pid_max = 4194304
# 同时提高文件描述符限制(相关配置)
fs.file-max = 2097152
fs.nr_open = 2097152
# 应用配置
sudo sysctl -p
|
| 阶段 | 操作 | 命令/方法 |
|---|
| 确认问题 | 检查 PID 使用情况 | cat /proc/sys/kernel/pid_max
ls /proc/[0-9]* | wc -l |
| 定位原因 | 统计进程分布 | ps -eo comm | sort | uniq -c | sort -rn |
| 紧急处理 | 终止异常进程 + 临时提高上限 | pkill -f "while true"
echo 4194304 > /proc/sys/kernel/pid_max |
| 永久解决 | 修改 sysctl 配置 | 编辑 /etc/sysctl.conf,添加 kernel.pid_max = 4194304 |
| 源头修复 | 关闭 MobaXterm 资源监控 | MobaXterm Settings → 取消资源监控选项 |
这次问题给我上了一课:即使是常用的连接工具,也可能在不经意间对系统造成影响。建议定期审查服务器的进程和资源配置,防患于未然。
本文记录于 2026-02-06,CentOS 7 系统环境