4

Linux 限制文件句柄数

 3 years ago
source link: https://liqiang.io/post/limit-open-file-description-in-linux?lang=ZH_CN
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在高负荷的 Linux 服务器或者代码出现了 Bug 的环境中经常出现 “too many open files”(以下简写为 TMOF) 的错误,这意味着一个进程已经打开太多的文件(文件描述符),无法再打开新的文件了。在 Linux 中,每个进程或用户的最大打开文件限制是有默认设置的,而且数值相当小。

在这篇文章中,我将介绍如何在 Linux 中检查当前最大打开文件的限制,以及如何为整个主机、单个服务或当前会话改变它。

TMOF 错误以及打开文件的限制

首先,让我们看看 “too many open files” 的错误出现在哪里。最常见的是在安装了 web 服务(NGINX/httpd )或数据库服务(MySQL/MariaDB/PostgreSQL)的机器上,当读取大量的日志时,就会出现这种情况。例如,当 Nginx 网络服务器超过 最大可打开文件 的限制时,你会看到一个错误:

  1. socket () failed (29: Too many open files) while connecting to upstream
图 1:Nginx 出现 too many open files 5349dcc3-9ed7-46f7-aa64-174cba2a53f2.png

使用这个命令,你可以得到系统可以打开的最大文件描述符的数量:

  1. [[email protected]]# cat /proc/sys/fs/file-max
  2. 22854988

当前用户的打开文件限制是 1024,你可以通过这条命令检查:

  1. [[email protected]]# ulimit -n
  2. 1024

其实这里有两种限制类型:硬限制和软限制,用户可以改变软限制(但是,软限制值不能超过硬限制),只有特权用户或根用户可以修改硬限制值。要显示软限制,可以运行以下命令:

  1. [[email protected]]# ulimit -Sn
  2. 65535

相应地,你可以通过这个命令查看硬限制:

  1. [[email protected]]# ulimit -Hn
  2. 65535

增加系统最大文件限制数

可以通过改变 Linux 操作系统中的限制来允许所有的服务打开大量的文件。为了让新的设置持久化,防止它们在服务器或会话重启后被重置,必须对 /etc/security/limits.conf 做出修改,具体为在这个文件中添加这些行:

  1. [[email protected]]# tail -2 /etc/security/limits.conf
  2. root soft nofile 65535
  3. root hard nofile 65535

增加单个服务的最大文件限制数

毕竟增加整个系统的文件描述符数量不是一个很好的事情,如果可以针对服务来控制的话,就更好了,事实上也是可以做的,这里我是使用 systemd 来做的:

  1. [[email protected]]# grep -A 2 Service /usr/lib/systemd/system/nginx.service
  2. [Service]
  3. LimitNOFILE=1024
  4. LimitNOFILESoft=1024
  5. [[email protected]]# systemctl daemon-reload
  6. [[email protected]]# systemctl restart nginx

验证一下文件的最大打开文件数:

  1. [[email protected]]# cat /proc/230490/limits | grep "Max open files"
  2. Max open files 1024 4096 files

修改当前会话的最大文件限制数

修改当前会话的文件描述符限制数可以很简单地通过 ulimit 命令做到:

  1. [[email protected]]# ulimit -n 2048

但是,很明显,在重新登陆之后,这个配置就会失效了,被恢复成 /etc/security/limits.conf 中的值,如果也想持久化一把,还可以这么改:

  1. [[email protected]]# grep "fs.file-max" /etc/sysctl.conf
  2. fs.file-max = 4096
  3. [[email protected]]# sysctl -p

这三个层级的先后顺序是:

  • 当系统启动的时候,先读取系统级别的句柄数限制(/proc/sys/fs/file-max)
  • 如果用户设置了(/etc/security/limits.conf),那么就会再次加载这份配置
    • 可以大于 file-max(这个只是建议值)
  • 如果用户设置了会话级别的,那么就使用会话级别覆盖
  • 如果用户设置了服务级别的,那么同样使用服务级别的设置覆盖

Soft 和 Hard 的区别是啥

没有本质区别,但是有些许的权限区别:

  • 只有 root 用户可以提高 hard
  • 非 root 用户和 root 运行的进程可以降低 hard
  • 所有用户都可以修改 soft,但是,不能超过 hard
    • 没有强制限制,但是即使超过了 hard,实际使用的时候也是选 soft 和 hard 中的小值

为什么限制和我期望的不一样

我通过 SSH 登陆系统之后,通过 ulimit 发现 fd 的限制居然是 1024,但是我查看了上面的所有地方,都没有发现 1024 的设置,并且都比 1024 大:

  1. [[email protected]]# ulimit -Sn
  2. 1024

那么是什么原因?通过搜索资料之后,发现这个原因如果没有指定用户级别的设置(/etc/security/limits.conf),那么默认的设置就是 1024。

lsof 为什么比 ulimit 多一些

主要原因是 lsof 包含链接的库,可执行文件,内存映射等等,这些不是走的进程的一切皆文件的处理方式。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK