### [VPS报Too many open files,别只调ulimit:先分清进程、systemd和文件句柄泄漏](https://www.jiyueip.com/article/13269) **Published:** 2026-07-29T15:39:54 **Author:** 斑斓助理 **Excerpt:** VPS出现Too many open files时,可能是单进程上限、systemd服务限制、全局文件表压力,或程序没有关闭文件和Socket。本文给出从报错来源、当前用量到安全调整与泄漏定位的排查顺序。 VPS出现`Too many open files`或`EMFILE`时,含义通常不是磁盘文件太多,而是某个进程无法再取得新的文件描述符。Linux用文件描述符表示普通文件、网络Socket、管道、事件通知等对象,所以故障可能表现为网站偶发502、数据库连接失败、日志无法写入,甚至新SSH会话或DNS请求异常。 最容易犯的错误是看到报错就把`ulimit -n`改得很大。上限太小确实可能限制正常并发,但如果程序不断打开文件或连接而不关闭,调大上限只会让故障晚一点发生。正确顺序是:**确认谁报错,读取该进程的真实限制,统计当前句柄及类型,再判断是容量规划还是泄漏**。 ## 先区分四个层级的限制 | 层级 | 常见查看位置 | 容易误判的地方 | | --- | --- | --- | | 当前Shell | `ulimit -Sn`、`ulimit -Hn` | 不能代表systemd服务 | | 单个进程 | `/proc/PID/limits` | 软限制与硬限制可能不同 | | systemd单元 | `LimitNOFILE` | 改完配置但未重载或重启 | | 系统文件表 | `file-nr`、`file-max` | 全局压力与单进程EMFILE混为一谈 | 应用日志若明确写出`EMFILE`,通常指该进程达到自己的描述符限制;若内核或多个无关服务同时异常,则还要检查系统级文件表、内存和连接压力。 ## 第一步:定位真正报错的服务与PID ``` systemctl --failed systemctl status your-service --no-pager journalctl -u your-service --since "-30 minutes" --no-pager systemctl show your-service -p MainPID -p LimitNOFILE ``` 不要只搜索网页入口的Nginx日志。请求可能经过反向代理、应用、数据库和队列,任一层耗尽描述符都可能在前一层表现为502或超时。记录首次报错时间、服务名、主PID、请求量和近期版本变更。 如果服务显示运行但公网访问失败,还应先用极跃圈的[VPS端口不通分层排查](https://www.jiyueip.com/article/13241)确认监听地址、防火墙和安全组,避免把网络入口问题误当成FD耗尽。 ## 第二步:读取进程的真实上限与当前用量 ``` cat /proc//limits | grep -i "open files" find /proc//fd -maxdepth 1 -type l | wc -l ls -l /proc//fd | head ``` `/proc/PID/limits`反映正在运行进程的实际限制,比登录Shell中的`ulimit`更可靠。当前FD数量接近软限制,能解释为什么新文件或Socket无法打开;但还不能说明这些句柄是否合理。 进程重启后PID会变化,自动采集时应通过systemd主PID、容器ID或服务发现获取当前实例,不要长期写死一个PID。 ## 第三步:看句柄是什么,而不只是数数量 ``` lsof -nP -p lsof -nP -p | awk '{print $5}' | sort | uniq -c | sort -nr ss -s ``` - **大量网络Socket:**核对并发、Keep-Alive、连接池、上游超时和客户端断开; - **大量重复日志文件:**检查轮转后应用是否仍持有旧文件; - **大量管道或匿名inode:**检查工作进程、IPC和事件循环是否正常回收; - **大量相同路径:**检查应用是否在请求循环中重复打开而未关闭; - **已删除文件:**文件名消失不代表进程已经释放句柄和磁盘空间。 `lsof`输出可能很大,也可能包含路径、用户名或连接信息。保存工单证据时应脱敏,不要公开Token、数据库凭据或客户地址。 ## 第四步:用趋势区分正常峰值与泄漏 一次快照只能说明当前状态。更有效的是每隔固定时间记录服务PID、FD数量、连接数、请求量和错误率: | 趋势 | 更可能的解释 | 下一步 | | --- | --- | --- | | 随流量上升,回落后下降 | 正常工作集或连接池 | 评估峰值余量 | | 到固定平台后稳定 | 池大小或缓存上限 | 核对配置是否符合容量 | | 相近负载下持续单向增长 | 文件、Socket或管道未关闭 | 在测试环境复现并做代码级分析 | | 重启归零后按相似斜率增长 | 泄漏嫌疑增强 | 关联请求类型、版本和调用栈 | 若FD增长同时伴随内存持续上升,可结合极跃圈的[VPS缓存、RSS与内存泄漏判断方法](https://www.jiyueip.com/article/13270)交叉确认,但文件描述符泄漏和内存泄漏不是同一个概念。 ## systemd服务应在单元层调整 确认正常峰值确实超过当前限制后,可使用systemd drop-in,而不是直接修改发行版自带单元文件: ``` sudo systemctl edit your-service ``` ``` [Service] LimitNOFILE=65536 ``` ``` sudo systemctl daemon-reload sudo systemctl restart your-service systemctl show your-service -p MainPID -p LimitNOFILE ``` `65536`只是示例,不是所有服务的推荐值。应根据已测峰值、每个连接的资源成本、程序自身上限和系统容量确定。数据库、反向代理、容器运行时也可能有独立配置,只有一层放大并不一定生效。 ## 容器里的限制要从宿主机和运行时一起看 容器内执行`ulimit`看到的值来自容器启动配置和宿主机约束。排查时同时确认容器内进程限制、容器运行参数、systemd对容器运行时的限制,以及宿主机文件表。不要只在运行中的容器里临时修改,因为重建后通常不会保留。 ## 系统级文件表接近上限时怎么判断 ``` cat /proc/sys/fs/file-nr cat /proc/sys/fs/file-max cat /proc/sys/fs/nr_open ``` 字段含义会随内核文档和版本表现,不能只凭一个数字机械判断。若多个服务同时无法打开文件,应结合内核日志、内存、进程FD分布和系统总量确认。调整`fs.file-max`前必须先找出主要消费者;全局上限变大不能修复单个服务的泄漏。 ## 恢复服务与根因修复要分开 1. 在明确影响和恢复路径后,受控重启故障服务以释放旧句柄; 2. 立即验证端口、健康检查、关键请求和日志写入; 3. 保留重启前后的FD数量与句柄类型; 4. 为FD使用率、增长速度和EMFILE日志设置告警; 5. 在测试环境复现泄漏,修复文件关闭、连接池或超时逻辑; 6. 根据正常峰值设置有证据的LimitNOFILE与容量余量。 不要用定时重启长期掩盖泄漏。临时重启可以恢复业务,但必须同时跟踪再次增长时间,否则下一次故障只会换个时点出现。 ## 结论 VPS报Too many open files时,先查看报错进程的真实限制和FD用量,再按句柄类型与时间趋势判断容量不足还是资源泄漏。Shell的ulimit、systemd的LimitNOFILE、容器限制和系统文件表属于不同层级;只有定位根因后再调整对应上限,才能避免“数值变大、故障照旧”。 **Tags:** Linux服务器, VPS, VPS监控, 服务器运维, 网络故障排查 **Categories:** 网络技术 ---