为什么 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-in | systemd 服务真正使用的值 |
| 内核全局 | 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 的文件类型分布,用来区分是限制配置偏小还是存在泄漏。