掘金 后端 ( ) • 2024-05-06 09:08

highlight: a11y-dark

前言

原本是想搞清楚一台服务器最多能建立多少个连接,在学习的过程中,发现能建立多少个连接受多个因素影响,其中一个因素就是 进程最大可打开文件数,我在自行查阅资料加请教专门搞容器的同事后,感觉这个知识点有点意思,故撰写此文以做记录。

正文

一. ulimit指令简析

要搞清楚进程最大可打开文件数这个问题,绕不开ulimit指令,该指令用于显示和设置当前会话当前用户所有进程的资源使用限制,例如打开文件数限制,相关指令如下。

# 显示打开文件数限制
ulimit -n
# 设置打开文件数限制
ulimit -n 2048

但是请注意,ulimit -n显示的打开文件数限制,一定是针对当前会话当前用户所有进程的,并不是对当前用户的限制,因为一个用户可以同时创建多个会话,同样的,ulimit -n 2048设置的打开文件数限制,也仅在本次会话中生效,如果开启下一次会话,打开文件数限制还是设置之前的值。

二. /etc/security/limits.conf文件简析

既然ulimit指令只能临时设置一次会话中某个用户的所有进程的资源限制,那肯定存在一种方式可以永久设置某个用户的资源限制,那就是修改 /etc/security/limits.conf文件。

我们可以在 /etc/security/limits.conf文件中添加如下的内容,一行就代表一个规则。

<domain> <type> <item> <value>

关于domain,可以选择设置如下值。

  • @group:应用于指定的用户组,例如@student
  • user:应用于指定的用户,例如ftp
  • @*:应用于所有用户组;
  • *:应用于所有用户。

关于type,可选值如下。

  • soft:表示软限制,超过软限制会告警;
  • hard:表示硬限制,超过硬限制会报错。

关于item,常用设置如下。

  • stack:最大堆栈大小,单位KB
  • cpu:最大CPU时间,单位MIN
  • fsize:最大可创建文件大小,单位KB
  • nproc:最大进程数;
  • nofile:最大可打开文件数。

至于value,就是一个具体的数字,表示设置的资源的大小。

比如可以进行如下设置。

* soft nofile 65535
* hard nofile 65535

也就是设置每个用户最大可打开的文件数为 65535

我们使用某个用户创建会话登陆后,通过ulimit -n显示的值实际就是去 /etc/security/limits.conf文件中进行规则匹配拿到的值,但是默认情况下 /etc/security/limits.conf可能并没有被添加规则,此时就会使用操作系统的默认值 1024

可以这么理解,在通过Shell登陆创建会话时,会去 /etc/security/limits.conf文件中匹配规则拿到当前会话当前用户所有进程的资源限制,此时拿到的资源限制就是实际生效的资源限制,我们可以通过ulimit来进行查询,也可以通过ulimit来临时的设置,但是通过ulimit设置的值并不会写入到 /etc/security/limits.conf文件中,所以通过ulimit设置的资源限制仅对当前会话生效,如果是下一个会话,还是会使用写在 /etc/security/limits.conf文件中的资源限制。同样的,修改了 /etc/security/limits.conf文件中的规则后,也不能立即对当前会话生效,需要断开会话并重新登陆一次才会生效。

三. Kubernetes中的Pod的资源限制

如果我们登陆到Kubernetes的集群,进入某个Pod,在Pod中执行ulimit -n,也是可以得到一个对最大可打开文件的限制的值的,但是查看 /etc/security/limits.conf文件,通常会发现里面一条规则都没有,既然没有规则,那么应该使用默认值吧,但是往往在Pod中执行ulimit -n得到的值也不等于 1024

要明白上面的情况,我们需要知道在启动一个容器时,这里以Docker为例,我们可以使用下面的指令来指定容器的实际生效的资源限制。

docker run -d --ulimit nofile=65535:65535 image

那在Kubernetes中,我们可以通过为容器运行时,例如为CRI-OContainerd等进行资源限制的配置,然后在运行容器时,就可以实现上述指令的效果。

还有一点,那就是Kubernetes的集群中的Pod,其资源限制的配置,和节点宿主机的配置,是相互独立。

总结

ulimit指令能够用于显示和设置当前会话当前用户所有进程的资源使用限制,如果使用ulimit指令设置资源使用限制,那么是临时生效,即仅在本次会话期间生效。

通过为 /etc/security/limits.conf文件添加资源限制规则,可以限制某个用户的所有进程的资源使用限制,无论使用这个用户创建了多少个会话,这个用户的对应的资源的使用不能超过 /etc/security/limits.conf文件中对应的限制。

在容器环境下,容器和宿主机的资源使用限制是可以分开设置的,如果是单独使用Docker,那么可以通过docker run -d --ulimit nofile=65535:65535 image在启动容器时指定资源限制,如果是使用Kubernetes,也能借助容器运行时CRI-OContainerd等进行资源的统一限制。

最后,/proc/sys/fs/file-max限制了整个系统里面的文件打开数,这个值一般比较大,如果想要设置这个值,可以修改文件值后再执行sysctl -p使得设置永久生效。