修复Linux中的“打开的文件太多”错误
1. 概述
在使用 Linux 服务器时,我们可能会遇到“打开的文件过多”错误。在本文中,我们将讨论此错误的含义以及如何修复它。
2. 什么是文件描述符?
从常规数据到网络套接字,Linux 中的一切都是文件! 文件描述符是 Linux 中打开文件的非负整数标识符。每个进程都有一个打开文件描述符表,在打开一个新文件时会附加一个新条目。
例如,当我们cat 文件时会发生什么?它打开通过open() 系统调用作为参数传递的文件,并为其分配一个文件描述符。然后,它通过文件描述符与文件交互——在这种情况下,只是为了显示它的内容——最后,通过close() 系统调用关闭它。
一个进程默认打开 三个文件描述符,用0表示stdin,1表示stdout,2表示stderr。
3. 检查打开的文件描述符
我们可以检查各种代理使用的文件描述符的数量,以确定我们的资源在哪里被使用。
3.1. 全球使用
如果我们想检查系统上打开的文件描述符的总数,我们可以使用awk 单行器在*/proc/sys/fs/file-nr*文件的第一个字段中找到它:
$ awk '{print $1}' /proc/sys/fs/file-nr
2944
3.2. 每个进程的使用
我们可以使用lsof 命令来检查进程的文件描述符使用情况。我们以caddy web 服务器为例:
$ sudo lsof -p $(pidof caddy)
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
caddy 135 caddy cwd DIR 254,1 4096 1023029 /etc/sv/caddy
caddy 135 caddy rtd DIR 254,1 4096 2 /
caddy 135 caddy txt REG 254,1 33595392 1542819 /usr/bin/caddy
caddy 135 caddy 0u CHR 5,1 0t0 12 /dev/console
caddy 135 caddy 1u CHR 5,1 0t0 12 /dev/console
caddy 135 caddy 2w FIFO 0,9 0t0 119 pipe
caddy 135 caddy 3u a_inode 0,10 0 6 [eventpoll:2,4,6,7,8,9,10,11,13,15,16,17,18,19,20,21,22,23,24,25,27,28,29,30,31,32,33,34]
caddy 135 caddy 4r FIFO 0,9 0t0 171 pipe
caddy 135 caddy 5w FIFO 0,9 0t0 171 pipe
caddy 135 caddy 6u IPv4 234 0t0 TCP localhost.localdomain:2019 (LISTEN)
caddy 135 caddy 7u IPv6 240 0t0 TCP *:443 (LISTEN)
caddy 135 caddy 8u IPv6 241 0t0 TCP *:80 (LISTEN)
caddy 135 caddy 9u IPv6 3819034 0t0 TCP 66.46.134.82.blogdemo.com:443->google.com:53222 (ESTABLISHED)
我们可以在NAME列下看到给定文件描述符所属的确切文件,而它的类型位于TYPE列下。查看以IPv6为类型的条目,我们可以得出结论,即使网络套接字也占用文件描述符,就像普通文件一样。
4. 文件描述符限制
一个进程对于它一次可以打开的文件描述符的数量有一定的限制。一种是软限制,任何非特权用户都可以更改,并且永远不能超过硬限制。非特权用户可以降低硬限制但不能再次提高它,而特权用户(例如root )可以根据需要提高和降低它。
4.1. 每会话限制
我们使用带有*-Sn标志的ulimit 命令检查软限制,使用-Hn*标志检查当前会话的硬限制:
$ ulimit -Sn
1024
$ ulimit -Hn
4096
4.2. 每进程限制
我们可以通过procfs文件系统检查一个进程的限制,给定它的 PID :
$ pid=31540
$ grep "Max open files" /proc/$pid/limits
Max open files 1024 4096 files
第二个和第三个字段分别对应软限制和硬限制。
4.3. 全局限制
**可以由所有进程组合打开的文件描述符总数存在系统范围的限制。*此限制存储在/proc/sys/fs/file-max*文件中:
$ cat /proc/sys/fs/file-max
1634185
5. 增加文件描述符限制
现在我们已经很好地理解了“打开的文件太多”错误背后的想法,让我们来看看解决它的各种方法。我们可以使用上一节中提到的命令来验证这些更改。在本节的示例中,我们使用500000来指代所需的限制。
5.1. 临时(每个会话)
让我们尝试使用ulimit -n命令为当前会话配置限制:
$ ulimit -n 4096
$ ulimit -n
4096
$ ulimit -n 8192
sh: error setting limit: Operation not permitted
**我们不能将限制设置为 4096 以上,因为在这种情况下这是硬限制。**并且如上所述,只有特权用户才能更改硬限制。
5.2. 按用户
我们可以通过在/etc/security/limits.conf*文件中添加几行*并重新登录来全局更改所有进程的软限制和硬限制:
* hard nofile 500000
* soft nofile 500000
root hard nofile 500000
root soft nofile 500000
在第一个字段中,我们指定限制影响的用户。我们使用glob 为系统上的所有用户设置了限制。
此外,在某些系统上,我们可能需要在/etc/pam.d/common-session中添加一行:**
session required pam_limits.so
5.3. 按服务
在基于systemd 的发行版上,我们使用systemctl 命令来配置特定服务的限制。以apache为例,我们用tee 为它创建一个filelimit.conf文件:
$ sudo mkdir -p /etc/systemd/system/apache.service.d/
$ sudo tee /etc/systemd/system/apache.service.d/filelimit.conf <<EOF
[Service]
LimitNOFILE=500000
EOF
现在,我们只需重新加载配置并重新启动服务:
$ sudo systemctl daemon-reload
$ sudo systemctl restart apache.service
5.4. 全球范围内
早些时候,我们在*/proc/sys/fs/file-max文件中检查了系统范围的聚合限制。我们可以通过在/etc/sysctl.conf*文件中添加一行来使用sysctl 对其进行配置:
fs.file-max = 500000
最后,我们需要运行sysctl -p命令重新加载配置文件。