当前位置:首页 > 文章列表 > 文章 > linux > systemd 服务里的 LimitNOFILE 为什么和 shell ulimit 不同

systemd 服务里的 LimitNOFILE 为什么和 shell ulimit 不同

来源:17golang原创 2026-10-07 00:08:22 0浏览 收藏

同一台 Linux 主机上,在终端执行 ulimit -n 得到 1024,服务进程却可能是 65536;这通常不是 systemd 失效,而是两个命令观察的进程上下文不同。shell 的 ulimit 改变当前 shell 的资源限制,并由它启动的子进程继承;systemd 服务由 manager 按单元配置启动,读取的是 manager 能提供的限制和 LimitNOFILE= 设置。

要点速览
  • LimitNOFILE= 设置服务进程的文件描述符 soft/hard limit,单值表示两者相同,soft:hard 可以分别设置。
  • 不要用当前终端的 ulimit -n 代替服务验证;优先查看 systemctl show、/proc/PID/limits 和 /proc/PID/fd。
  • 修改 drop-in 后必须 daemon-reload 并重启服务,且旧程序若使用 select,不要盲目把 soft limit 提到 1024 以上。
systemd LimitNOFILE 与 shell ulimit 的启动上下文和 soft hard limit 关系说明图
图1:启动上下文说明图,展示 shell ulimit 与 systemd LimitNOFILE 的作用域差异。
systemd 服务的 LimitNOFILE 和 shell 里跑 ulimit 看到的值不一样,核心原因是两套限制的生效层级、继承逻辑和优先级规则完全不同,系统启动时的硬限制并不会直接透传给后续 systemd 拉起的服务进程,很多人踩坑就是没理清几者的覆盖关系。

LimitNOFILE 和 shell ulimit 处在两条启动上下文里

ulimit -n 是 shell 内建命令,它显示或修改当前 shell 的文件描述符限制。你在终端里执行它,只能直接说明这个终端及其后代进程的限制;已经由 PID 1 的 systemd manager 启动的服务,并不会回头读取你后来在终端里改过的值。

LimitNOFILE= 属于 systemd 执行环境配置,最终通过 Linux 的进程资源限制生效。配置写成单个数字时,soft 和 hard 使用同一个值;写成 65536:131072 时,服务可先使用 65536,进程在具备相应权限和实现支持时再把 soft limit 提高到 hard limit。这里的“文件”也包括 socket、管道等文件描述符,不只是磁盘文件。

先读取服务自己的限制,不要猜 manager 的默认值

排查时先取得主进程 PID,再同时看单元解析结果和进程内核视图。下面的命令只展示检查路径,输出中的数值应以你的服务为准。

# 替换为实际单元名,先查看 systemd 解析后的限制
systemctl show myapp.service -p MainPID -p LimitNOFILE

# 读取服务主进程的 soft/hard limit;PID=0 说明服务没有运行
pid="$(systemctl show -p MainPID --value myapp.service)"
if [ "$pid" -gt 0 ]; then
  awk '/Max open files/ {print}' "/proc/$pid/limits"
  printf '当前 fd 数量:'
  find "/proc/$pid/fd" -mindepth 1 -maxdepth 1 -type l | wc -l
fi

systemctl show回答“单元当前解析到什么”,/proc/PID/limits回答“这个服务进程真正拿到了什么”,而 /proc/PID/fd 的数量只是当前使用量。使用量接近 soft limit 时,才更像是 fd 耗尽;如果限制值不对,继续加业务重试没有意义。

观察位置它说明什么不能据此推出什么
终端 ulimit -n当前 shell 的 soft limit不能代表 systemd 服务
systemctl show单元和 manager 的解析结果不等于某个旧进程已经重启
/proc/PID/limits目标进程实际 soft/hard limit不等于当前已打开 fd 数
/proc/PID/fd进程当前 fd 使用量不说明限制来自哪一层

用 drop-in 明确设置并完成一次重启

生产环境更适合给单元增加 drop-in,而不是直接改发行版提供的主 unit 文件。下面的示例把服务 soft limit 设为 65536、hard limit 设为 131072;数值要按应用是否使用高 fd、内核资源和旧 API 兼容性评估。

# 创建本地 drop-in,避免覆盖软件包提供的 unit 文件
sudo systemctl edit myapp.service

# 在编辑器中写入以下 [Service] 配置
[Service]
LimitNOFILE=65536:131072

# 让 manager 重新读取 unit,并重启服务创建新进程
sudo systemctl daemon-reload
sudo systemctl restart myapp.service

# 重启后重新读取服务进程的实际限制
systemctl show myapp.service -p MainPID -p LimitNOFILE

如果只执行了 daemon-reload,它只刷新配置,不会改变已经运行的服务进程;如果只重启而没有刷新,可能继续使用旧解析结果。改完后再次读取 /proc/$pid/limits,这是判断是否真正生效的关键。

常见边界:继承、权限和旧接口

systemd system instance 的服务限制通常可以独立设置,但 user service 受到 user manager 启动时已有的上限约束,单元配置不能凭空把 hard limit 抬得比 manager 能提供的更高。此时要追查 user manager 的启动环境、PAM limits 或承载它的 system service,而不是反复修改服务文件。

还要区分“能打开多少 fd”和“程序是否能处理高编号 fd”。systemd 文档特别提醒,Linux 上传统 select 不能处理编号高于 1023 的 fd;使用 poll、epoll 或其他适配实现的程序,才适合评估更高的 soft limit。提升限制不是性能开关,也不能代替 cgroup 的内存、任务数和连接池配置。

systemd 服务 LimitNOFILE 配置来源与 proc 运行时证据的排查结构图
图2:排查结构图,把单元配置与服务进程实际限制、fd 使用量对应起来。

相关问题

为什么修改 /etc/security/limits.conf 后服务仍不变?

该文件主要通过 PAM 影响登录会话;systemd system service 不一定经过你的交互登录 PAM 链路。服务应优先在 unit 或 manager 层明确配置,再从服务 PID 验证。

LimitNOFILE=65536 为什么仍然打开失败?

可能是 soft limit、应用内部连接池、权限、内存压力或其他内核资源先到边界。先看 /proc/PID/limits 与实际 fd 数量,再定位应用报错。

改完配置后看哪个值最可信?

以重启后目标服务 PID 的 /proc/PID/limits 为准;systemctl show用于解释配置来源,终端 ulimit只作当前 shell 的参考。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go sql.Named 怎么让驱动按名称绑定参数Go sql.Named 怎么让驱动按名称绑定参数
上一篇
Go sql.Named 怎么让驱动按名称绑定参数
Go errors.Unwrap 为什么不能直接展开 errors.Join
下一篇
Go errors.Unwrap 为什么不能直接展开 errors.Join
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    355次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    416次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    424次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    378次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    200次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码