首页/系统/信创系统运维速查/systemd 服务的文件句柄限制
服务与运维65 条

systemd 服务的文件句柄限制

高并发服务报 Too many open files 时改单元 LimitNOFILE:用 drop-in 单独放开并 daemon-reload 后重启;systemd 服务默认继承 PID1 的限制,需要显式配置。

信创系统运维速查系统更新于 2026-10-13

为什么 limits.conf 不管用

systemd 启动的服务默认继承 PID1 的资源限制,而不是 /etc/security/limits.conf 里的用户限制。所以高并发服务报 Too many open files 时,改 limits.conf 往往不生效,正确做法是在单元里设置 LimitNOFILE,或用 drop-in 文件覆盖。改完必须重新加载并重启服务,再用 systemctl show 核对最终生效值。

基本信息

单元参数LimitNOFILE、LimitNPROC、LimitCORE
推荐位置/etc/systemd/system/<单元>.d/10-limits.conf
生效步骤daemon-reload 后 restart 服务
核对命令systemctl show <服务> -p LimitNOFILE
全局上限内核参数 fs.file-max

典型使用场景

  • Nginx、Tomcat、Java 服务在高并发下报句柄不足
  • 数据库连接数或线程数被单元限制挡住
  • 需要抓核心转储排障时放开 LimitCORE
  • 批量数据处理任务需要更多进程数,避免创建失败
  • 统一基线,给同类服务下发相同的资源限制

配置 drop-in

配置 drop-in
mkdir -p /etc/systemd/system/nginx.service.d         # 建 drop-in 目录
# 写入 /etc/systemd/system/nginx.service.d/10-limits.conf
#   [Service]
#   LimitNOFILE=65535      # 文件句柄上限
#   LimitNPROC=65535       # 进程数上限
systemctl daemon-reload                              # 让 systemd 重新读取单元
systemctl restart nginx                              # 重启生效
systemctl show nginx -p LimitNOFILE -p LimitNPROC     # 核对最终值
cat /proc/$(pgrep -f nginx | head -1)/limits | grep 'open files'   # 进程侧确认

限制层级对照

层级配置位置说明
用户会话/etc/security/limits.conf只对登录会话生效
服务单元单元文件或 drop-insystemd 服务真正使用的值
内核全局fs.file-max所有进程的总上限
systemd 默认system.conf 中默认值PID1 的默认参数
全局句柄上限用 sysctl 调整:在 /etc/sysctl.d/ 下写 fs.file-max 再执行 sysctl -p 应用;单元限制之外还要看这个全局值,否则单个服务放开后仍可能被内核挡住。

排查句柄不足的步骤

  • 先看进程侧实际限制:/proc/<PID>/limits 里打开文件数那一行
  • 再核对单元生效值:systemctl show <服务> -p LimitNOFILE
  • 确认内核全局上限:sysctl fs.file-max 与 fs.nr_open
  • 查是谁占着句柄:lsof -p <PID> 按类型统计分布
  • 评估连接数与打开文件数是否与业务规模匹配
句柄不足还有一种来源是连接未及时释放:排障时同时看 ss -s 的连接统计与 lsof 的文件类型分布,用来区分是限制配置偏小还是存在泄漏。

易错点

  • 改完 limits.conf 重启服务发现没变化:systemd 服务不读该文件,必须用 LimitNOFILE
  • 改完没重新加载或没重启:生效值保持旧限制,要用 systemctl show 核对而不是凭感觉
  • 只放开句柄数不放开进程数:高并发下仍会创建进程失败,两项一起配
  • 直接改发行版自带单元文件:系统升级会覆盖,覆盖内容要写进 drop-in 目录
  • 只为报错的服务调大限制而不看增长曲线:句柄持续增长通常意味着连接或文件泄漏,调大只是把问题推迟

数据来源与参考

  • man 5 systemd.exec(LimitNOFILE)
  • man 5 sysctl.d
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌