更新: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
查看特定服务的当前定义的值 - 查看服务运行时实际应用的值,获取正在运行的服务的 PID,
systemctl show -p MainPID yourservername
,cat /proc/<pid>/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 11000000
* hard nofile 11000000
root hard nofile 11000000
root soft nofile 11000000
注意,最后两行是我实践发现的,我用的是 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