飘在云端

东西南北,海角天涯

· 备查 · · 335次浏览

永久修改 Linux 最大文件句柄 Too many open files

更新:2024-07-12

因为某些原因采坑了,发现之前内容只对非服务类型的生效,对于 systemd 管理的服务,有点特殊,需要在自身的服务文件明确定义,如果没有明确在服务自身配置定义值,会继承 父进程 / systemd 进程的限制

然而这里有个坑,你以为是继承系统级的限制?并不是,它实际上有自己的一个默认限制的值

systemd 默认限制在 /etc/systemd/system.conf/etc/systemd/user.conf,默认情况下可能部分被注释掉了

我是 Ubuntu v22.04.4 LTS,查看 system.conf 默认值,发现默认情况下全被注释掉了

#DefaultLimitNOFILE=1024:524288
#DefaultLimitNPROC=

systemd 并不会自动使用系统级限制,如 fs.nr_open 这个系统级的绝对全局上限作为其默认值

在没有在自身服务配置明确定义的情况下,实际限制是以下值中的最小值

  • 系统级的绝对全局硬限制(如 fs.nr_open),所有的值超过它都是无效的
  • systemd 默认限制,它自己的一个默认值配置:,在 /etc/systemd/system.conf/etc/systemd/user.conf
  • 父进程的限制,继承父进程的值

查看当前限制:

  • 可以使用 systemctl show <service-name> |grep LimitNOFILE 查看特定服务的当前定义的值
  • 查看服务运行时实际应用的值,cat /proc//limits 文件

下面是我只定义了系统级的绝对全局上限, fs.nr_open=11000000,然后我随便查看某个运行的 systemd 服务

systemctl show sshd |grep LimitNOFILE
LimitNOFILE=524288
LimitNOFILESoft=1024

显示我没定义的情况下,sshd 服务使用的值是这些

查看运行时应用的实际值是什么

root@www:~/.ssh# cat /proc/2269866/limits
Limit Soft Limit Hard Limit Units
......
Max processes 7447 7447 processes
Max open files 1024 1048576 files
......

即使是这样,仍然不建议去修改所有 systemd 服务设置一个通用的默认值,可以在 /etc/systemd/system.conf 中取消注释并设置 DefaultLimitNOFILE 和 DefaultLimitNPROC,给他们定义明确值
之后重启 systemctl daemon-reload

可能会有大问题,这样所有服务都能无限制使用了,可能会有非预期的问题

示例:
具体是修改 [Service] 项,修改如下关键字段 LimitNPROC LimitNOFILE

下面是一个资源密集型的后台服务示例

[Unit]
Description=这是一个高并发、资源密集型的服务
After=network.target NetworkManager.service systemd-networkd.service

[Service]
User=root
Group=root
Type=simple
LimitCORE=0
LimitNPROC=11000000  # 允许服务创建大量进程,以处理大量并发请求
LimitNOFILE=11000000 # 设置文件描述符限制为 11,000,000,如果这里不设置,可能会使用 systemd 默认值
#CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME
#AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME
Restart=always
ExecStartPre=/usr/bin/sleep 1s
ExecStart=/root/demo/ljasdfhnfd -c /root/.config/sigh/config.conf
ExecReload=/bin/kill -HUP $MAINPID

[Install]
WantedBy=multi-user.target


某台小鸡上面跑的 Seafile 的 ElasticSearch 太吃文件句柄数了(因为是 Java 开发的) ,也可能是我设置不当,导致 Seafile 运行几个小时就报 Too many open files。

网上搜索的资料都很不负责任,这里推荐下面引用的大佬的微信公众号【开发内功修炼】,详细说明了原因和修改办法,并且深度扒了内核源码和详细分析,还给了漫画图解,非常深刻!看完之后简直是醍醐灌顶。

刨根问底儿,看我如何处理 Too many open files 错误!https://mp.weixin.qq.com/s/GBn94vdL4xUL80WYrGdUWQ
漫画 | 一台Linux服务器最多能支撑多少个TCP连接? https://mp.weixin.qq.com/s/Lkyj42NtvqEj63DoCY5btQ
漫画 | 理解了TCP连接的实现以后,客户端的并发也爆发了! https://mp.weixin.qq.com/s/ta6upubg0o1w03YGUo8Trg

本文在以上内容增加了一点变化,增加了 root hard nofile 相关的配置,因为测试时发现,对于 root 用户,必须要特别指定用户名,才能生效,不想细看的话,就这么操作,永久性修改:

vim /etc/sysctl.conf

修改或增加如下内容:

fs.nr_open=11000000  
fs.file-max=11000000 

然后 sysctl -p ,使其立刻生效。

vim /etc/security/limits.conf,在文件末尾追加如下四行:

*  soft  nofile  10000000
*  hard  nofile  10000000
root  hard    nofile   10000000
root  soft    nofile   10000000

注意,最后两行是我实践发现的,我用的是 root 用户,修改完之后重启系统也没生效,查询谷歌之后,发现部分系统,还需要特别指定 root 用户名。

修改完之后重启系统,以上这套方案可以支撑同时打开 一千万个文件描述符,远远大于默认 1024 的限制。

然后执行 ulimit -a 查看限制。

测试环境:Ubuntu 20.04.3 LTS,内核:Linux 5.15.8-rt23-xanmod(这是一个第三方内核,见 https://www.xanmod.org/),用户权限:root

也在 CentOS 7.9 / CentOS 8.2 测试通过。

输出如下:

root@ubuntu:~# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31571
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 10000000
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 31571
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
评论 (0条)