问题现象
- 初始错误:
ssh protocol handshake error, socket error: connection reset by peer - 后续在服务器端执行命令时出现:
-bash: fork: retry: resource temporarily unavailable - 根本原因:系统进程数(pid)耗尽,无法创建新进程(包括 ssh 登录所需的 shell)。
排查与修复步骤(按时间顺序)
1. 紧急恢复系统创建进程的能力
目的:临时调高系统允许的最大 pid 数量,使系统能再次 fork 新进程。
# 临时修改内核参数(立即生效,无需重启) echo 1000000 > /proc/sys/kernel/pid_max # 检查当前用户进程数限制(可选) ulimit -u # 若限制过小,可临时解除 ulimit -u unlimited
2. 统计各用户进程数量,定位异常
目的:找出哪个用户占用进程数最多。
ps -eo user=|sort|uniq -c|sort -nr
输出:
28168 root
28148 oracle
58 grid
...
发现 root 和 oracle 用户各有约 2.8 万个进程,远超正常范围。
3. 进一步统计每个用户下各命令的进程数量
目的:确定具体是哪个程序(command)造成了进程爆炸。
# 统计 root 用户各进程数量(取前10) ps -u root -o comm --no-headers | sort | uniq -c | sort -nr | head -10
输出(示例):
52 bioset
51 kdmflush
7 ext4-rsv-conver
6 sshd
5 mingetty
4 bash
4 usmgeneral
3 udevd
3 oks_rbld
3 java
root 用户下未见异常,数量可控。
# 统计 oracle 用户各进程数量(取前10) ps -u oracle -o comm --no-headers | sort | uniq -c | sort -nr | head -10
输出:
27436 sendmail
27436 crond
558 postdrop
115 oracle
18 server
18 replicat
10 extract
1 sshd
1 oraagent.bin
1 ggsci
锁定元凶:oracle 用户下堆积了约 2.7 万个 sendmail 和 2.7 万个 crond 进程,完全失控。
4. 清理异常进程
目的:终止这些失控进程,释放 pid 资源。
# 杀掉 oracle 用户下所有 sendmail 进程 pkill -u oracle sendmail # 杀掉 oracle 用户下所有 crond 进程 pkill -u oracle crond # 若上述无效或仍有残留,可强制终止该用户所有进程(注意:会中断 oracle 数据库) pkill -9 -u oracle
5. 验证清理效果
# 查看当前总进程数 ps -e | wc -l # 分别查看各用户进程数 ps -u root | wc -l ps -u oracle | wc -l
进程数应降至正常水平(通常几百到几千)。
6. 根除病因——检查 oracle 用户的定时任务
目的:防止重启后问题复现,因为大量 crond 进程通常来自循环执行的 cron 任务。
# 查看 oracle 用户的 crontab crontab -u oracle -l # 也可直接查看 cron 文件 cat /var/spool/cron/oracle
发现异常任务(如频繁调用 sendmail 或死循环脚本),立即注释或删除相应行。
7. 永久固化系统配置(避免重启后再次耗尽)
目的:将临时修改写入配置文件,使系统重启后仍保持较大的 pid 上限和用户进程限制。
# 永久修改内核最大 pid 数 echo "kernel.pid_max = 1000000" >> /etc/sysctl.conf sysctl -p # 永久解除(或调高)用户进程数软硬限制 echo "root soft nproc unlimited" >> /etc/security/limits.conf echo "root hard nproc unlimited" >> /etc/security/limits.conf echo "oracle soft nproc unlimited" >> /etc/security/limits.conf echo "oracle hard nproc unlimited" >> /etc/security/limits.conf
8. 重启 ssh 服务并验证连接
目的:确保 ssh 服务状态正常,并能接受新连接。
# 重启 ssh 服务 systemctl restart sshd # 从另一终端尝试 ssh 连接,确认成功
关键命令速查表
| 步骤 | 命令 | 作用 |
|---|---|---|
| 紧急恢复 | echo 1000000 > /proc/sys/kernel/pid_max | 临时调高 pid 上限 |
| 查看总进程数 | ps -e | wc -l | 统计全部进程数 |
| 统计各用户进程 | ps -eo user=|sort|uniq -c|sort -nr | 找出异常用户 |
| 统计某用户各命令 | ps -u oracle -o comm --no-headers | sort | uniq -c | sort -nr | head -10 | 定位具体失控程序 |
| 清理进程 | pkill -u oracle sendmail pkill -u oracle crond | 杀死指定用户的特定进程 |
| 查看 crontab | crontab -u oracle -l | 检查定时任务 |
| 固化配置 | 见上文第7步 | 永久生效 |
总结
故障根源是 oracle 用户的 cron 任务反复拉起 sendmail/crond 进程,导致 pid 耗尽。
通过临时调高 pid 上限、清理失控进程、修复定时任务并固化内核/用户限制,彻底解决了 ssh 连接拒绝和 fork 失败的问题。
完成后,ssh 连接恢复正常。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论