Linux 服务怎么限制文件描述符:LimitNOFILE、启动用户与日志检查
来源:17golang原创
时间:2026-08-26 07:34:33 493浏览 收藏
线上服务出现“Too many open files”时,先别急着把机器级限制一口气调大。systemd 启动的服务有自己的进程上下文,当前终端里执行 ulimit -n 65535,并不会自动改变已经由 systemd 拉起的进程。更稳妥的做法是给目标 unit 写入 LimitNOFILE,再用进程实际限制和日志确认配置确实生效。
LimitNOFILE是 systemd 服务级配置,适合把文件描述符上限跟着 unit 管理。- 改完 drop-in 后必须执行
daemon-reload和服务重启,并用/proc/PID/limits复核。 - 上限不是越大越好,启动用户、连接池、日志轮转和内核资源要一起检查。
- 发布前保留
systemctl cat、systemctl show与journalctl的结果,回滚时只需移除 drop-in。
先区分当前 Shell 限制和服务进程限制
同一台机器上,下面两条命令可能给出不同答案:
ulimit -n systemctl show order-api.service -p LimitNOFILE
第一条只反映当前 Shell 的资源限制;第二条查看 systemd 记录给 unit 的属性。真正处理请求的是服务进程,所以最终还要拿到 PID 检查 /proc/PID/limits。如果只改了登录用户的 shell 配置,服务重启后仍可能回到旧上限。

用 drop-in 给 order-api.service 设置上限
不要直接改发行版提供的 unit 文件,使用 drop-in 更容易审计和回滚:
sudo systemctl edit order-api.service
在打开的编辑器中写入:
[Service] LimitNOFILE=65535
这里的数值要按连接数、日志文件、监听 socket 和程序自身打开的临时文件估算。一个服务如果有 2 万个长连接,再加上数据库连接池、文件缓存和运行时开销,65535 可能是合理的起点;如果只是小型定时任务,直接套用这个数字反而会掩盖句柄泄漏。
重载、重启后检查配置来源和实际值
配置保存后按固定顺序执行:
sudo systemctl daemon-reload sudo systemctl restart order-api.service systemctl is-active order-api.service systemctl cat order-api.service systemctl show order-api.service -p User -p LimitNOFILE -p FragmentPath
systemctl cat 用来确认 drop-in 确实被合并;systemctl show 则能看到 systemd 当前解析后的属性。这里别只看“active”,服务能启动不代表限制已经按预期传递给进程。
先取 PID,再检查进程上下文:
pid=$(systemctl show -p MainPID --value order-api.service) ps -o pid,user,comm -p "$pid" grep -i 'open files' "/proc/$pid/limits" ls "/proc/$pid/fd" | wc -l
最后一条是当前打开句柄数的近似快照,不等于峰值。对长期运行的服务,建议把它和进程指标、连接池指标一起观察,避免仅凭一次检查下结论。

启动用户和日志权限也要一起验收
服务的 User= 决定了它能打开哪些目录和日志文件。LimitNOFILE 配置正确,但启动用户无法访问日志目录,仍然会在启动后反复报错。发布检查至少要记录下面几项:
| 检查项 | 命令 | 通过标准 |
|---|---|---|
| 配置来源 | systemctl cat order-api.service | 能看到目标 drop-in |
| 运行用户 | systemctl show ... -p User | 与目录权限设计一致 |
| 进程上限 | /proc/PID/limits | Soft/Hard 值符合预期 |
| 启动日志 | journalctl -u order-api.service -b | 无权限或句柄相关错误 |
查看本次启动日志时,优先使用:
journalctl -u order-api.service -b --no-pager -n 100 journalctl -u order-api.service -b -p warning..alert --no-pager
如果日志里出现 EMFILE、Permission denied 或某个路径无法创建,先确认是描述符耗尽、目录权限还是应用自己的资源泄漏。不要把所有错误都归因于 LimitNOFILE。
生产环境的数值边界与回滚方法
建议先在一台实例上改动,压测或回放一段与生产接近的连接流量,观察句柄数量是否持续上涨。若句柄数接近上限,优先查连接关闭、文件句柄泄漏和日志轮转;提高上限只能延后故障。
回滚时删除 drop-in 中的两行配置,再重载并重启:
sudo systemctl revert order-api.service sudo systemctl daemon-reload sudo systemctl restart order-api.service systemctl show order-api.service -p LimitNOFILE
如果 unit 里还有其他人工 drop-in,不要直接使用 revert 覆盖它们;先用 systemctl cat 确认文件来源,再删除本次创建的片段。回滚也要检查服务状态和最近一轮日志。
常见问题
改了 /etc/security/limits.conf,systemd 服务会跟着变吗?
不能直接假设会变。该文件主要影响登录会话,systemd unit 应使用自身的资源限制配置,并以进程实际值为准。
LimitNOFILE 设置成 unlimited 可以吗?
不建议把它当作默认修复。无限制会放大句柄泄漏和内核资源消耗,应该先按连接模型设定明确上限。
systemctl show 已经是 65535,为什么应用仍报 EMFILE?
可能是服务运行后确实耗尽了上限,也可能是应用或依赖进程没有正确关闭文件。继续检查当前 FD 数量、连接池和日志轮转,而不是只看 unit 属性。
重启后限制又恢复了怎么办?
用 systemctl cat 检查 drop-in 是否位于正确目录,再确认是否执行过 daemon-reload。如果配置由部署工具管理,还要检查下一次发布是否覆盖了该文件。
发布前的最小检查清单
把 systemctl cat、systemctl show、/proc/PID/limits 和 journalctl -u ... -b 四类结果留档,再进行下一台实例的变更。这样即使问题出在应用资源泄漏,也能快速证明 systemd 的配置是否真正生效。
-
426 收藏
-
387 收藏
-
242 收藏
-
238 收藏
-
402 收藏
-
467 收藏
-
415 收藏
-
文章 · linux | 11小时前 | 性能优化 · Linux · 系统调用 · io_uring · 异步IO · Linux 异步IO io_uring SQPOLL IORING_SETUP_SQPOLL484 收藏
-
222 收藏
-
450 收藏
-
222 收藏
-
252 收藏
-
446 收藏
-
文章 · linux | 19小时前 | Linux · 故障排查 · auditd · 系统审计 · 日志运维 · Linux 审计日志 auditd auditctl backlog limit exceeded 队列溢出391 收藏
-
345 收藏
-
295 收藏
-
458 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习