limit 详解

今天在使用 Prometheus 时遇到了问题,报错 err=”list block dirs /prometheus/data/: open /prometheus/data/: too many open files”, 经查询发现,系统默认的普通用户系统最大打开文档数为 1024,Prometheus 数据太多导致该问题,将普通用户的这个限制适当的上调即可。

经过这个事情发现,对 limit 的掌握并不熟悉,特意搜索了 limit 的相关信息整理在这里,学习以及备忘。

环境说明:

1
2
CentOS Linux release 7.4.1708 (Core)
Linux hulk 3.10.0-693.el7.x86_64

Linux是有文档句柄限制的,而且Linux默认普通用户都是1024,root 用户没有限制,作为生产系统使用很容易就达到这个数量

操作系统各方面的资源都是非常紧缺的, ulimit 可以起到很大的作用,它是一种简单并且有效的实现资源限制的方式。

ulimit 用于限制 shell 启动进程所占用的资源,支持以下各种类型的限制:所创建的内核文档的大小、进程数据块的大小、Shell 进程创建文档的大小、内存锁住的大小、常驻内存集的大小、打开文档描述符的数量、分配堆栈的最大大小、CPU 时间、单个用户的最大线程数、Shell 进程所能使用的最大虚拟内存。同时,它支持硬资源和软资源的限制。

作为临时限制,ulimit 可以作用于通过使用其命令登录的 shell 会话,在会话终止时便结束限制,并不影响于其他 shell 会话。而对于长期的固定限制,ulimit 命令语句又可以被添加到由登录 shell 读取的文档中,作用于特定的 shell 用户。

参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
-a:显示目前资源限制的设定;
-c <core文档上限>:设定core文档的最大值,单位为区块;
-d <数据节区大小>:进程数据节区的最大值,单位为KB;
-f <文档大小>:shell所能建立的最大文档,单位为区块;
-H:设定资源的硬性限制,也就是管理员所设下的限制;
-m <内存大小>:指定可使用内存的上限,单位为KB;
-n <文档数目>:指定同一时间最多可开启的文档数;
-p <缓冲区大小>:指定管道缓冲区的大小,单位512字节;
-s <堆叠大小>:指定堆叠的上限,单位为KB;
-S:设定资源的弹性限制;
-t <CPU时间>:指定CPU使用时间的上限,单位为秒;
-u <进程数目>:用户最多可开启的进程数目;
-v <虚拟内存大小>:指定可使用的虚拟内存上限,单位为KB。

limit.conf 文档说明

limits.conf 文档是 Linux PAM(插入式认证模块,Pluggable Authentication Modules)中 pam_limits.so 的配置文档,pam_limits 模块对用户的会话进行资源限制。对系统访问资源有一定保护作用。

一个 shell 的初始limits就是由 pam_limits 设定的,用户登录后,pam_limits 会给用户的shell设定在 limits.conf 定义的值。

pam_limits模块对用户的会话进行资源限制,然后 /etc/pam.d/ 下的应用进程调用 pam_***.so 模块。
pam_limits 的设定值也是 per-process 的。
pam_limits 的设置是永久生效的。

limit.conf 文档的格式如下:

1
<domain>        <type>  <item>  <value>
  • <domain> 可以是如下:
1
2
3
4
- user   可以是一个用户名
- @group 可以是一个组名,但是要加@ ,例如:@group
- * 通配符*来做所有用户的限制
- the wildcard %, can be also used with %group syntax, for maxlogin limit
  • <type> 只能是下列三个值之一:
1
2
3
4
5
    - soft  当前系统生效的设置值
- hard 系统中所能设定的最大值
- - 用 - 就表明同时设置了 soft 和 hard 的值。

soft 的限制不能比hard 限制高
  • <item> 可以是下列的选项之一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- core           限制内核文档的大小(KB)               - limits the core file size (KB)
- data 最大数据大小(KB) - max data size (KB)
- fsize 最大文档大小(KB) - maximum filesize (KB)
- memlock 最大锁定内存地址空间(KB) - max locked-in-memory address space (KB)
- nofile 打开文档的最大数目 - max number of open file descriptors
- rss 最大持久设置大小(KB) - max resident set size (KB)
- stack 最大栈大小(KB) - max stack size (KB)
- cpu 以分钟为单位的最多 CPU 时间 - max CPU time (MIN)
- nproc 进程的最大数目 - max number of processes
- as 地址空间限制(KB) - address space limit (KB)
- maxlogins 此用户允许登录的最大数目 - max number of logins for this user
- maxsyslogins 在系统上可以登录的最大数量 - max number of logins on the system
- priority 优先运行该用户的进程 - the priority to run user process with
- locks 用户可以持有的文档锁的最大数量 - max number of file locks the user can hold
- sigpending 最大等待信号数 - max number of pending signals
- msgqueue POSIX消息队列使用的最大内存 - max memory used by POSIX message queues (bytes)
- nice 最大的优先级允许提高到值:[-20, 19] - max nice priority allowed to raise to values: [-20, 19]
- rtprio 最大的实时优先级 - max realtime priority
  • <value> 可以选择如下之一:
1
2
3
4
5
    - 0          最小值
- x 范围内的整数
- unlimited 不做限制

最大值不要超过系统限制的最大值。

查看当前 limit 限制

使用 ulimit -a 即可查看当前的 limit ,open files 对应的就是当前登陆用户的最大文档打开数量。(也可以用 ulimit -n 快速查看)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[[email protected] ~]
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 31847
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
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) 31847
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
[[email protected] ~]#

临时修改 limit 限制

很多时候为了检查问题,需要临时修改设置以确认问题的原因,或者不希望永久生效,那么可以使用如下命令进行快速设置

1
ulimit -n 4096

很多文章称 ulimit -n 只允许设置得越来越小,比如先执行了ulimit -n 1000,在执行ulimit -n 1001,就会报 “cannot modify limit: Operation not permitted” 错误。
这个其实也是不准确的说法。首先要搞清楚,任何用户都可以执行ulimit,但root用户和非root用户是非常不一样的。

非root用户只能越设置越小,不能越设置越大。
root 用户没有限制,可以随意增加或者缩小。

永久修改 limit 限制

上述的设置只能临时生效,如果想要永久生效,那么要换其他方法。
想要永久生效,有2种方法。

将上述命令写到登陆后默认加载的文档

该方法对应的操作是,如果需要
所有用户有效,将 ulimit -n 4096 添加到 /etc/profile 。 所有用户登录后都会检查该文档,并加载其中的配置。
特定用户有效,将 ulimit -n 4096 添加到对应用户的 ~/.bash_profile 。 用户登录后都会检查自己家目录下的 .bash* 文档,并加载其中的配置。

个人并不建议使用这种方式进行修改,原因是修改不好或者在某些未考虑周全的情况下,会导致用户无法登录系统,人为增加故障率

修改 limit.conf 配置文档

在 /etc/security/limits.conf 文档中按照文档的规则添加配置例如

设置 test 的最大打开数为8196

1
test - nofile 8196

如果对某一用户或者某中特定的场景有很多的 limit 设置,那么不建议直接修改 /etc/security/limits.conf 文档,这样管理起来成本太大。
这种情况下,可以在 /etc/security/limits.d/ 目录下新建 .conf 结尾的配置文档进行单独管理,pam_limits.so 在执行时也会一并加载。

在系统里,/etc/security/limits.d/ 目录下的文档会覆盖 /etc/security/limits.conf 的内容,所以如果在 limits.conf 文档里配置的内容不要和 limits.d 目录下的内容冲突,如果担心冲突,可以将配置都放在 limits.d 下进行管理。

覆盖的顺序是,

  1. limits.d 目录下的会覆盖 limits.conf 文档。

  2. limits.d 目录下按照英文字母顺序进行加载,后加载的覆盖前边加载的 。

  3. 数字应该按照 01 、02、……09、10 这样的顺序进行排序。

修改系统总限制。

上边讲了很多种查看和修改的方法,一般情况下是够用了,那么现在来说说特殊情况。上边提过,最大文档打开数量最大不要超过系统的限制。

那么怎么查看呢?系统将这个数字存储在了 /proc/sys/fs/file-max 文档,直接查看就好。/proc/sys/fs/file-nr 文档里存储了整个系统目前使用的文档句柄数量。

1
2
3
4
5
[test@hulk ~]$ cat /proc/sys/fs/file-max
807968
[test@hulk ~]$ cat /proc/sys/fs/file-nr
1408 0 807968
[test@hulk ~]$

那么怎么修改这个值呢?有2个方法,一个是临时的,一个是永久的。

临时修改系统限制

1
echo  6553560 > /proc/sys/fs/file-max

永久修改系统限制

修改 /etc/sysctl.conf, 加入下列配置,由于修改了系统的内核参数,所以需要使用 sysctl -p 来使新的参数生效。

1
fs.file-max = 6553560

注意

  • 数值设置根据实际情况进行设置,不要一味的增大,否则会导致系统故障无法运行;
  • 网上说修改了 limit.conf 以后如果要生效,必须要确保 pam_limits.so 文档被加入到启动文档中。查看 /etc/pam.d/login 文档中有:session required /lib/security/pam_limits.so 。我在 CentOS 7 的系统里找了/etc/pam.d/login 文档,发现没有 pam_limits.so , 也可以正常生效;
  • 修改系统最大值时或许可以参考本地磁盘或者存储的相关指标,不要“超标”;
  • limits.conf 和sysctl.conf区别在于limits.conf是针对用户,而sysctl.conf是针对整个系统参数配置。

参考链接

======================
Erdong, A Linux user !