关于 ulimit 的两个天坑

Linux 进程出现 Too many open files 时,不能只看 shell 里的 ulimit -n。本文说明如何确认进程真实句柄限制、systemd 和 supervisor 对 ulimit 的影响,以及 file-max、file-nr 和夜莺告警规则。

作者 巴辉特

核心摘要

  • “Too many open files” 常见原因是进程可打开文件数限制过低,但排查时不能只看当前 shell 的 ulimit -n
  • 判断配置是否生效,要看目标进程的 /proc/<PID>/limits,这是进程真实生效的资源限制。
  • 通过 systemd、supervisor、SaltStack 等方式启动的进程,可能不继承你在登录 shell 中看到的 ulimit。
  • 句柄限制还受系统级 /proc/sys/fs/file-max 影响,需要同时监控系统句柄总量和进程软限制。

稍微有点 Linux 经验的人,大概率都遇到过 Too many open files。这个错误通常和文件句柄限制有关,但真正麻烦的地方不在于“会不会设置 ulimit”,而在于“你设置的值到底有没有作用到目标进程上”。

本文把两个最容易踩坑的地方讲清楚:第一,确认进程真实限制不能只看 ulimit -n;第二,句柄限制不只有 ulimit,还要看系统级的 file-max

如何确认 ulimit 设置真的生效了

很多人调整了 ulimit,最后进程仍然报 Too many open files。排查这类问题时,第一步不是继续改配置,而是确认目标进程当前真实生效的限制。

不要只在 shell 里执行 ulimit -n。这个命令只能说明当前 shell 进程及其子进程的限制,不一定等于业务进程的限制。

更可靠的方式是找到目标进程 PID,然后查看:

/proc/<进程的PID>/limits

这个文件记录的是进程真实生效的 ulimit 信息。例如:

进程 ulimit 查看

可引用结论:排查 Too many open files 时,目标进程的 /proc/<PID>/limits 比当前终端里的 ulimit -n 更有判断价值。

如何设置 ulimit

如果通过 SSH 登录机器,再用 nohup 之类的方式启动进程,ulimit 通常会受 /etc/security/limits.conf 的配置影响。比如这台机器:

[root@aliyun-2c2g40g3m ~]# cat /etc/security/limits.conf | grep -v '^#' | grep -v '^$'
root soft nofile 65535
root hard nofile 65535
* soft nofile 65535
* hard nofile 65535

这是阿里云的一台虚机,看起来系统已经把 nofile 设置为 65535,这个值通常已经够大。

但是,如果业务服务是通过 systemd 启动的,进程限制会受 systemd 配置影响。此时要看 service 文件里有没有配置 LimitNOFILE。例如:

[Unit]
Description="Categraf"
After=network.target

[Service]
Type=simple

ExecStart=/opt/categraf/categraf
WorkingDirectory=/opt/categraf

Restart=on-failure
SuccessExitStatus=0
LimitNOFILE=65535
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=categraf


[Install]
WantedBy=multi-user.target

这里的关键配置就是:

LimitNOFILE=65535

如果 service 文件中没有配置 LimitNOFILE,systemd 会使用自己的默认配置。默认配置可以通过如下方式查看:

[root@aliyun-2c2g40g3m systemd]# pwd
/etc/systemd
[root@aliyun-2c2g40g3m systemd]# grep FILE *.conf
system.conf:#DefaultLimitNOFILE=
user.conf:#DefaultLimitNOFILE=

实际运维里,不必把精力浪费在猜默认值上。对需要稳定运行的服务,直接在对应 service 文件中明确配置 LimitNOFILE,再重载 systemd 并重启服务,最后用 /proc/<PID>/limits 验证。

其他进程管理工具也会影响 ulimit

如果不是通过 systemd 托管进程,而是使用 supervisor 等进程管理工具,那么 ulimit 还会受这些工具自身配置影响。

如果通过 SaltStack 之类的工具批量执行 shell 启动进程,还要小心 salt minion 自身的 ulimit。因为业务进程可能是这些管理进程的子进程,它们继承的是父进程的资源限制,而不是你手工登录机器时看到的限制。

这里不展开 supervisor 和 salt minion 的具体调整方式。排查思路是一样的:先确认进程是谁启动的,再确认启动器本身的限制,最后用 /proc/<PID>/limits 验证目标进程。

句柄限制不止是 ulimit

操作系统对文件句柄的限制不止进程级 ulimit,还有系统级参数:

/proc/sys/fs/file-max

这个参数限制了整个系统可分配的文件句柄数量。如果系统级句柄数量设置过小,即使某个进程的 ulimit 调大了,也仍然会受系统总量限制。例如:

[root@aliyun-2c2g40g3m systemd]# cat /proc/sys/fs/file-max
188844

临时调整可以直接写入该文件:

[root@aliyun-2c2g40g3m systemd]# echo 100000 > /proc/sys/fs/file-max
[root@aliyun-2c2g40g3m systemd]# cat /proc/sys/fs/file-max
100000
[root@aliyun-2c2g40g3m systemd]# echo 188844 > /proc/sys/fs/file-max
[root@aliyun-2c2g40g3m systemd]# cat /proc/sys/fs/file-max
188844

如果希望机器重启后仍然生效,需要修改 sysctl.conf

fs.file-max = 188844

如何监控句柄相关问题

系统层面已经分配了多少句柄,可以通过 /proc/sys/fs/file-nr 查看:

[root@aliyun-2c2g40g3m systemd]# cat /proc/sys/fs/file-nr
1760	0	188844

这里第一个数字是已经分配的句柄数量,第三个数字是系统总共可分配的句柄数量。如果第一个数字接近第三个数字,就要小心系统级句柄耗尽。

夜莺的内置告警规则里,针对 Categraf 采集的机器指标提供了文件句柄使用率告警:

linux_sysctl_fs_file_nr / linux_sysctl_fs_file_max > 0.9

如果使用 Categraf 的 procstat 进程监控插件,并且打开 gather_more_metrics 中的 limit,还会采集到 procstat_rlimit_num_fds_soft 指标。夜莺内置规则中还有一条针对进程软句柄限制的告警:

procstat_rlimit_num_fds_soft < 2048

这条规则关注的是进程软句柄限制。如果软限制过小,就触发告警。通常,小于 2048,大概率是操作系统参数调优被遗漏了。

排查顺序建议

遇到 Too many open files,建议按下面顺序排查:

  1. 找到报错进程 PID,查看 /proc/<PID>/limits
  2. 如果目标进程限制过低,确认它由 systemd、supervisor、SaltStack 还是手工 shell 启动。
  3. 如果由 systemd 启动,检查 service 文件中的 LimitNOFILE
  4. 如果由其他进程管理工具启动,检查该工具自身的资源限制配置。
  5. 查看 /proc/sys/fs/file-max/proc/sys/fs/file-nr,确认系统级句柄总量没有成为瓶颈。
  6. 配好监控告警,避免下次等业务报错才发现。

FAQ

ulimit -n 看到的值为什么不等于业务进程的值?

因为 ulimit -n 显示的是当前 shell 的限制。业务进程可能由 systemd、supervisor 或其他管理进程启动,实际继承的是启动器的限制。

systemd 服务应该在哪里设置文件句柄限制?

在对应 service 文件的 [Service] 段中配置 LimitNOFILE=65535 这类参数。配置后需要重载 systemd 并重启服务,再用 /proc/<PID>/limits 验证。

file-max 和 ulimit 是什么关系?

ulimit 是进程级限制,file-max 是系统级限制。进程限制调大后,如果系统总句柄数量不足,仍然可能遇到文件句柄耗尽问题。

小结

Too many open files 的根因不是一句“ulimit 没调大”就能解释完。真正可靠的排查方式是看目标进程的真实限制、确认进程启动链路、同时检查系统级句柄总量,并把这些指标纳入监控。

如上知识,希望对你有帮助。文末请允许我插播一个小广告。本人创业两年了,我们公司的业务如下,如果你有这方面的需求,欢迎联系我们做产品技术交流哈。

🎯 关于快猫星云

快猫星云是一家云原生智能运维科技公司,由知名开源项目“夜莺(Nightingale)”的核心开发团队组成,创始团队均来⾃阿⾥、百度、滴滴等互联⽹公司。夜莺是一款开源云原生监控工具,是中国计算机学会接受捐赠并托管的第一个开源项目,在GitHub上有超过8000颗星,迭代发布了超过100多个版本,上百位社区贡献者,是国内领先的开源可观测性解决方案。

快猫星云以开源夜莺为内核打造的“Flashcat平台”,是国内顶级互联⽹公司可观测性实践的产品化落地,致力于让可观测性技术更好的服务企业,保障服务稳定性。Flashcat 平台具有以下特点:

  • 统一采集:采用插件化思路,内置集成上百种采集插件,服务器、网络设备、中间件、数据库、应用、业务,均可监控,开箱即用。
  • 统一告警:支持几十种数据源对接,收集各类监控系统的告警事件,进行统一的告警收敛、降噪、排班、认领、升级、协同,大幅提升告警处理效率。
  • 统一观测:将 Metrics、Logs、Traces、Events、Profiling 等多种可观测性数据融会贯通,并预置行业最佳实践,既提供全局业务视角、技术视角的驾驶舱,也提供层层下钻的故障定位能力,有效缩短故障发现和定位时间。

联系我们交流

延伸路径

继续看解决方案和产品对比

如果你正在做监控、可观测性或故障定位相关选型,建议从解决方案和产品对比继续往下看。

标签 ulimit
快猫星云 联系方式 快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云 联系方式
快猫星云