ulimit与系统资源限制

前言

Linux操作系统对用户、进程都有默认的资源使用限制,如果设置不当会影响进程的正常工作。生产环境部署新的应用系统或者中间件,都需要考虑修改默认的资源使用限制。通过命令ulimit可以看到当前session资源限制的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## ulimit -a 可以看到用什么参数修改ulimit值
ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 63374
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1048576
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) unlimited
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

## 设置 -n 修改open files值
ulimit -n 1048576

修改方式

不同Linux发行版之间各个参数的修改方式上有些差异。但是总体上还是可以按照如下流程修改,确保修改操作的安全性:确认参数最大值->临时修改/永久修改->生效与验证

tips: 确认最大值是为了保证临时修改的参数的值不超过参数本身系统设定的最大值,否则可能引发系统问题

实际案例

在实际生产环境中,最常见的需要修改的是用户可以打开的最大文件描述符个数和使用的最大进程个数。下面介绍两种资源限制引起的典型异常

Too many open files

在网络应用中,一个TCP都会占用一个文件描述符,如果这个耗尽了,新来的连接直接会报这个错。资源限制引发的错误里面,文件描述符数量不够引发too many open files异常是最常见的。

通过ulimit配合一些常见的命令,我们可以找到消耗文件描述符多的进程

1
2
3
4
5
6
7
8
9
10
11
### 查询系统打开的文件描述符总数
awk '{print $1}' /proc/sys/fs/file-nr

### 根据pid查询进程打开的文件描述符
sudo lsof -p $(pid)

### 查看进程文件描述符限制
grep "Max open files" /proc/$pid/limits

## 按照open file 排序
lsof -n |awk '{print$2}'|sort |uniq -c |sort -nr |more

确认最大值

修改的时候注意不要超过操作系统设置的上限值,否则可能影响正常的用户登入和操作。不同参数最大值都不一样,例如文件描述符的最大可设置值如下,在配置ulimit的时候,nofile千万不要超过nr_open:

1
2
3
4
5
### 系统所有进程打开最大文件描述符可以设置的最大值,默认值1553179
cat /proc/sys/fs/file-max

### 单个进程可分配的最大文件数,默认值1048576
cat /proc/sys/fs/nr_open

tips: 如果忘记含义了,可以使用man proc 查看释义

临时修改

修改临时针对当前session生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## ulimit -a 可以看到用什么参数修改ulimit值
ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 63374
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1048576
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) unlimited
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

## 设置 -n 修改open files值
ulimit -n 1048576

永久生效(无需重启)

配置优先级
/etc/security/limits.d下的配置大于/etc/security/limits.conf

修改/etc/security/limits.conf文件

修改永久生效,需要重启机器

1
2
3
4
5
6
7
## 修改下面文件中的值,具体的格式在这个文件注释中也有说明
vi /etc/security/limits.conf
## 比如针对所有用户,修改用户最大进程数和用户最大文件描述符数,文件添加下面两行。软硬限制都一起加上。
* hard nproc 1048576
* soft nproc 1048576
* hard nofile 1048576
* soft nofile 1048576

tips:

  • 软限制是个告警值,实际上是可以超过的,只是不能超过硬限制,一般设置成一样就可以
  • nofile的值一定不要超过/proc/sys/fs/nr_open中的值,否则会无法正常登入

检查UsePAM 是否开启

如果显示UsePAM yes,则开启,否则需要先开启(RedHat注意开启风险)。

1
2
3
# WARNING: 'UsePAM no' is not supported in Red Hat Enterprise Linux and may cause several
# problems.
cat /etc/ssh/sshd_config | grep UsePAM

检查/etc/pam.d/system-auth

文件中需要包含如下内容

1
session required pam_limits.so

检查/etc/pam.d/login

需要包含如下内容

1
session required /lib64/security/pam_limits.so

tips: docker容器需要设置ulimit的话参考stackover flow回答

最佳时间

Java应用程序访问文件的时候务必记得close对应的文件对象,建议使用try-resource避免FD泄露

参考资料