Linux prlimit 怎么限制单个服务的文件句柄:RLIMIT_NOFILE、软硬上限与服务管理器验收
来源:17golang原创
时间:2026-08-25 00:43:33 304浏览 收藏
一个 Linux 服务明明只处理几百个连接,运行几天后却开始报 Too many open files。这时只改当前 shell 里的 ulimit -n 往往没有用,因为真正运行服务的进程可能由 systemd 启动,继承的是另一套限制。更稳妥的处理方式是先用 prlimit 查看目标 PID,再把软上限、硬上限和实际打开数量分别验收。
RLIMIT_NOFILE有软上限和硬上限两层,进程只能把软上限调到不超过硬上限的值。prlimit --pid PID --nofile=soft:hard只作用于目标进程,适合先做可回退的现场验证。- 长期配置要写进服务单元的
LimitNOFILE=,再通过/proc/PID/limits核对实际启动结果。 - 上限变大不等于泄漏消失,仍要结合
/proc/PID/fd数量和错误日志判断句柄是否持续增长。

先确认报错来自哪个 PID 和哪一层上限
先定位到实际运行的生产服务进程PID,不要用终端里手动临时启动的测试进程替代来做验证:
pgrep -af 'worker|api-server' cat /proc//limits | grep 'open files' ls /proc/ /fd | wc -l
/proc/ 里的 open files 会显示 soft 和 hard 两个值,/proc/ 的数量则是当前已打开描述符的近似值。若当前数量只差几百就撞上 soft 上限,先记录增长速度和句柄类型,再决定是否临时放大;如果数量持续上升,单纯改上限只会把故障推迟。
prlimit 的最小用法与软硬边界
针对正在运行的目标进程,你可以先直接读取当前的配置值:
sudo prlimit --pid--nofile
需要做现场验证的时候,显式指定要修改的软上限和硬上限:
sudo prlimit --pid--nofile=65536:65536 sudo prlimit --pid --nofile
命令参数里冒号左边是 soft 软限制,右边是 hard 硬限制。普通日常用户通常只能往下调低限制,或者把软限制调整到不超过当前硬限制的区间;要上调硬限制一般需要更高的系统权限,而且如果进程已经被上层服务管理器预设了更小的边界,就算你在当前终端执行prlimit命令,也没法越过那个提前设好的边界。
| 状态 | 判断 | 下一步 |
|---|---|---|
| soft 接近当前已打开fd数量 | 很快就可能触发文件打开失败的报错 | 核对硬限制数值和服务本身的启动配置 |
| soft 配置值不小但fd数量还在持续上涨 | 大概率是句柄泄漏或者连接回收逻辑异常 | 按fd的具体类型定位资源持有者 |
| 临时改完soft/hard之后重启服务配置又变回旧值 | 之前的修改仅针对单个临时PID生效 | 把限制写入服务单元配置,重启后做全链路验收 |
服务启动配置要落在 LimitNOFILE
如果你的服务是由 systemd 托管的,把长期生效的限制配置写进对应unit的drop-in配置片段里,别只改当前登录shell的临时值:
sudo systemctl edit my-api.service
在打开的编辑器里追加对应配置项:
[Service] LimitNOFILE=65536
保存配置之后重新加载unit配置并重启对应服务:
sudo systemctl daemon-reload sudo systemctl restart my-api.service systemctl show my-api.service -p LimitNOFILE pid=$(systemctl show -p MainPID --value my-api.service) grep 'open files' /proc/$pid/limits
这里的验收重点是“新 PID 的 limits”,因为旧进程的限制不会随着 unit 文件改变而自动刷新。systemctl show 反映服务管理器的配置值,/proc/$pid/limits 才是最终进程实际继承到的值,两者最好同时保留。
把句柄数量和文件类型一起查清楚
把句柄限制上调之后,你仍然需要确认服务没有在无节制地累积连接、管道或者匿名临时文件:
pid=$(systemctl show -p MainPID --value my-api.service)
printf 'fd_count='; find /proc/$pid/fd -mindepth 1 -maxdepth 1 -type l | wc -l
sudo ls -l /proc/$pid/fd | sed -n '1,20p'
sudo lsof -n -p "$pid" | awk 'NR>1 {print $5}' | sort | uniq -c | sort -nr
如果统计到大量socket都指向同一个下游地址,通常要回头调整连接池参数、空闲超时和重试策略;如果统计到大量标记为deleted的文件句柄,就要检查日志轮转之后旧句柄没有释放的问题;如果pipe和eventfd的数量持续上涨,就要核对worker进程的生命周期管理逻辑。按fd类型分类排查,比单纯看总fd数值要更有参考价值。

回滚和发布前检查
临时调整prlimit仅适合快速确认“当前句柄上限确实是服务的性能瓶颈”。如果调完之后业务错误率下降,但fd总数还在持续上涨,应该先把配置回退,优先修复资源回收逻辑;如果fd数量稳定、相关报错完全消失,再把经过验证的正确数值写入版本化管理的drop-in配置里。
- 调整前先记录原来的 soft 值、hard 值和当时的fd统计总量。
- 用
prlimit对单个 PID 做一次可观察的变更。 - 在相同的流量窗口下观察fd打开数量、业务错误率和服务响应延迟的变化。
- 确认无泄漏后写入
LimitNOFILE,重启并核对新 PID。 - 如果出现异常,直接删掉新增的drop-in配置或者把旧值恢复回去,再重新做一次全量状态检查。
常见问题
修改当前终端的 ulimit 后,服务为什么没变化?
你的服务可能由 systemd 或者其他守护进程拉起,和当前操作的shell根本不在同一个父进程链路里。必须直接在服务unit配置里写入限制、重启服务之后,再取新生成的PID做校验。
soft 和 hard 应该设置成一样吗?
如果希望服务进程自身在运行态还能自主上调软限制,可以把硬限制设得比预期最大值更高;如果不需要这类动态调整的弹性,把软限制和硬限制设成同一个经过验证的数值,后续排查核对的时候会更省事。
fd 数量没到上限却出现 Too many open files,为什么?
还要同步排查进程内的其他资源限制、单次请求的临时流量峰值、子进程或者工作线程的继承限制规则,以及报错发生时你是不是查错了对应业务的PID。
LimitNOFILE 修改后一定要重启吗?
是。unit 配置影响新启动的进程,旧 PID 的资源限制不会自动更新;重启后要用新 PID 的 /proc/limits 复核。
把最终值和实际使用量放在一起验收
文件句柄限制的迁移结果可以用三组数据收口:服务 unit 的 LimitNOFILE、新 PID 的 RLIMIT_NOFILE、以及同一流量窗口内的 fd 增长曲线。三者一致,只能说明上限配置正确;只有数量不再无边界增长、错误率恢复,才说明根因也被处理了。
-
160 收藏
-
105 收藏
-
426 收藏
-
387 收藏
-
242 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习