Too many open files:句柄上限的三层配置与真实案例
高并发服务跑一段时间后报 Too many open files,重启就好,过几天又出现。这通常不是限制太小,而是句柄在泄漏。
但先要把三层限制配对:内核 fs.file-max、用户 limits.conf、进程自身(systemd 的 LimitNOFILE 会覆盖前两者)。
先说结论
先确认限制值,再查是否泄漏,最后才考虑调大。 只调大不查泄漏,等于把问题推迟几天。
- ulimit -n 与 cat /proc/
/limits 对比 - systemd 服务加 LimitNOFILE=65535
- lsof -p
| wc -l 看句柄数与类型 - 找出增长最快的类型(socket/文件/管道)
- 应用层修连接泄漏
先把问题说清楚
systemd 启动的服务不读 limits.conf,必须用 LimitNOFILE 显式设置——这是最常见的坑。
句柄泄漏的典型形态:连接用完没 close、异常分支漏了 finally、事件监听器只加不减。
具体怎么做
按顺序执行,每步都验证完再进下一步:
- ulimit -n 看当前 shell 限制,cat /proc/
/limits 看进程真实限制 - 按句柄类型统计:lsof -p
| awk '{print $5}' | sort | uniq -c | sort -rn - 观察增长曲线:每分钟统计一次,线性增长基本就是泄漏
- 系统层调 fs.file-max,用户层调 limits.conf,服务层加 LimitNOFILE
- 应用层修复泄漏点,并加句柄数监控
参数与成本对照
把关键数值摊开,方便判断该选哪条路:
| 层级 | 配置位置 | 说明 |
|---|---|---|
| 内核 | /etc/sysctl.conf fs.file-max | 全系统上限 |
| 用户 | /etc/security/limits.conf | 登录会话生效 |
| 服务 | systemd unit LimitNOFILE | 覆盖前两者 |
| 进程 | ulimit -n(继承) | 取决于启动方式 |

几个容易踩的坑
下面这些是最常见的错误做法:
- 只改 limits.conf 不重启会话:不生效
- 用 systemd 起服务却只改 limits.conf:同样不生效
- 把上限调到 100 万却不看内存:句柄也占内存
- 忽略容器内的 nofile 限制与宿主不同
最后补两句
句柄问题的正确顺序是:看限制 → 看类型 → 看增长 → 修泄漏 → 再调上限。
工具是手段,理解机制才是能力。命令记不住没关系,知道「该看什么」就够了。
评论 (3)
照着做了一遍,确实少走弯路。第二步最容易漏,建议顺手加个检查清单。
比「一键脚本」有用多了,知道为什么比知道怎么做重要。
补充一句:不同版本行为会变,动手前先确认自己的版本号。
发表评论