背景

最近在 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 导致的问题,需要在使用端进行修复:

  1. 关闭 MobaXterm 资源监控功能

    • 打开 MobaXterm → Settings → Configuration → Terminal
    • 取消勾选 “Monitor remote server resources”
  2. 清理已连接的会话中的残留脚本

    • 如果之前开启了资源监控,可能需要在每个服务器上手动清理残留的监控脚本
  3. 检查并删除可能残留的启动脚本

    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 系统环境