Linux 服务器报 Too many open files,连 SSH 都登不上,怎么救急?
问题
服务器突然所有服务拒接,新开 SSH 直接报 “Too many open files in system”,终端也登不进去。人在机器外,怎么先把门打开,再治根?
原因
这是系统级文件句柄耗尽:某个进程打开的文件、连接只开不关(句柄泄漏),把全系统的句柄额度吃光,连建立一个 SSH 会话所需的新文件都分配不出来。它和"某个端口被占用"是两码事——那是单点冲突,这是容量被吃光。处置思路是先恢复入口,再找泄漏元凶,最后抬高护栏。
解决
第一步:保住现有入口。已经登录着的会话千万别退出,退了可能再也连不上;一个可用会话都没有,就走服务器自带的带外管理口(iDRAC、iBMC、HDM 的虚拟控制台),这是句柄耗尽时最稳的通道。
第二步:登进去先看水位:cat /proc/sys/fs/file-nr,输出三个数依次是"已分配/空闲/上限",第一列贴着第三列,坐实系统级耗尽。
第三步:揪出泄漏大户:
lsof -n | awk '{print $2}' | sort | uniq -c | sort -rn | head -5
列出打开文件数最多的几个 PID。如果 lsof 本身都跑不动,用兜底版直接读内核:
for p in /proc/[0-9]*; do echo $(ls $p/fd 2>/dev/null | wc -l) ${p#/proc/}; done | sort -rn | head -5
第四步:ps -fp <PID> 确认是什么进程,systemctl restart <服务名> 重启(非 systemd 管的用 kill),句柄一放,SSH 立刻能登——先恢复入口再慢慢查。
第五步:治本加护栏。临时抬高上限:sysctl -w fs.file-max=655350,并把 fs.file-max = 655350 写进 /etc/sysctl.conf 持久化;单个服务的上限在对应 systemd 单元里加一行 LimitNOFILE=65535。至于泄漏本身,多半是程序里连接或文件没关,要回到代码里修,光抬高上限只是续命。
预防
- 监控里加一条 file-nr 使用率曲线,缓慢爬升的泄漏提前几周就有苗头。
- 新服务上线前做一轮压测,专门观察句柄数涨不涨、涨了回不回落。
- 带外管理口的账号日常保持可用,别等救急那天才发现密码进不去。