资源限制

资源限制 ( resource limitrlimit ),是 Linux 内核控制 用户进程 资源占用的机制。

rlimit 可控制的系统资源包括: 内存文件CPU调度进程数 等。优秀系统管理员设置合适的 rlimit 值,避免某个用户或某个进程占用过多系统资源而拖垮系统。

本文介绍设置 rlimit 的来龙去脉,具体 rlimit 值属于 系统调优 范畴,暂不全面涉及。

ulimit命令

ulimit 是一个 Shell 内置命令,由于查看、调整当前 Shell 进程的 rlimit 值。以 bash 为例,查看所有 rlimit 值:

  1. $ ulimit -a
  2. core file size (blocks, -c) 0
  3. data seg size (kbytes, -d) unlimited
  4. scheduling priority (-e) 0
  5. file size (blocks, -f) unlimited
  6. pending signals (-i) 3709
  7. max locked memory (kbytes, -l) 16384
  8. max memory size (kbytes, -m) unlimited
  9. open files (-n) 1024
  10. pipe size (512 bytes, -p) 8
  11. POSIX message queues (bytes, -q) 819200
  12. real-time priority (-r) 0
  13. stack size (kbytes, -s) 8192
  14. cpu time (seconds, -t) unlimited
  15. max user processes (-u) 3709
  16. virtual memory (kbytes, -v) unlimited
  17. file locks (-x) unlimited

注解

资源项详细介绍请参考文章末尾处附录的表格。

也可以查看某项资源的限制,以进程打开 文件描述符 数( RLIMIT_NOFILE )为例:

  1. $ ulimit -n
  2. 1024

由此可见,当前 Shell 进程最多只能打开 1024文件描述符 ,由该 Shell 启动的程序也是如此。接着实现一个简单的程序,不断创建 套接字 ( socket ),以验证这一点:

  1. $ python detect-max-fd.py
  2. error no: 24
  3. error string: Too many open files
  4. fd range: [3, 1023]

显然,程序无法无限地创建 套接字 。当 文件描述符 达到 rlimit 限制时,相关 系统调用 将失败,错误码为 EMFILE ,即 Too many open files 。成功打开的套接字文件描述符范围从 31023 ,与 1024 的上限相吻合。

注解

进程前三个文件描述符 012 分别是 stdinstdout 以及 stderr

当然了,可以通过 ulimit 调整 文件描述符 上限:

  1. $ ulimit -Sn 512

注解

-S 选项指定 软限制 ,资源软硬限制之别请见下一小节。

这时,进程能打开的 文件描述符 变少了:

  1. $ python detect-max-fd.py
  2. error no: 24
  3. error string: Too many open files
  4. fd range: [3, 511]

注解

detect-max-fd.py源码以及原理剖析请查看文章附录,位于末尾处。

软硬之分

资源限制有软硬之分, 软限制 ( soft )和 硬限制 ( hard )。

软限制 是一般意义的资源限制, 直接作用于用户或者进程ulimit 默认返回软限制:

  1. $ ulimit -n
  2. 1024

也可通过 -S 选项显式指定返回 软限制

  1. $ ulimit -Sn
  2. 1024

由上一小节,我们知道用户可以将软限制调低或调高。如果普通用户可以无限制调高, rlimit 将失去限制用户的意义。为此,内核引入了 硬限制 ,规定了软限制调整的上限。

ulimit 查看 硬限制 需要指定 -H 选项:

  1. $ ulimit -Hn
  2. 1048576

调整 软限制 时,不能超出 硬限制 ,否则报错:

  1. $ ulimit -Sn 10485760
  2. -bash: ulimit: open files: cannot modify limit: Invalid argument

同样,可以将 硬限制 调低:

  1. $ ulimit -n 1024

注解

设置 rlimit 限制时,未指定软硬,则同时设置。

一旦调低 硬限制 ,便没有后悔药,无法再调高了(除非出动 root 用户):

  1. $ ulimit -Hn 1048576
  2. -bash: ulimit: open files: cannot modify limit: Operation not permitted

因此,软硬限制之别可总结为以下几点:

  • 软限制 直接起作用;
  • 软限制 不能超出 硬限制
  • 硬限制 只能调低;

配置文件

通过配置文件设置 rlimit 值,可永久生效,也可突破 ulimit 不能调高 硬限制 的局限。配置文件 limits.conf 位于 /etc/security/limits.conf ,格式如下:

  1. root soft nofile 1000000
  2. root hard nofile 1000000
  3. * soft nofile 1000000
  4. * hard nofile 1000000

每个配置行由 4 个字段组成,分别是:

  • ( domain )
  • 类型 ( type )
  • 资源项 ( item )
  • ( value )

其中, 可以是用户或者用户组(以 @ 开头,例如 @admin ), * 则表示任意用户;类型 分为两种,分别对应 软限制 ( soft )和 硬限制 ( hard );资源项 列表见附录。

配置编辑完毕后,重新登录即可生效,无需重启。

注解

limits.confpam_limits.so 的配置文件,而 pam_limits.soLinux插入式认证模块 ( Pluggable Authentication Modules 简称 PAM )的子模块。

根据 PAM 机制,应用程序启动时,按 /etc/pam.d 配置加载 pam_xxxx.so 模块。/etc/pam.d 下包含了 loginsshdsusudo 等程序的 PAM 配置文件,因此用户重新登录时,将调用 pam_limits.so 加载 limits.conf 配置文件。

附录

rlimit资源项

表格-1 资源项
项目ulimit选项含义
as-v地址空间 (虚拟内存空间)大小限制
chroot chroot 目录
core-c核心转储文件 大小限制
cpu-tCPU执行时间 限制
data-d进程数据段 大小限制
fsize-f文件大小 限制
locks-x文件锁数量 限制
memlock-l锁定内存 ( locked-in-memory )地址空间大小限制
maxlogins 用户登录数 限制
maxsyslogins 系统登录数 限制
msgqueue-q消息队列内存 限制
nice-enice值上限
nofile-n文件描述符 数量限制
nproc-u进程数量 限制
priority
rss-m常驻内存 ( resident set )大小限制
rtprio-r实时调度优先级
rttime
sigpending-i排队信号 ( pending signals )数量限制
stack-s进程栈大小 限制

detect-max-fd.py源码

这是一个 Python 程序,循环创建套接字,促使进程打开文件描述符达到上限:

  1. from socket import (
  2. socket,
  3. AF_INET,
  4. SOCK_STREAM,
  5. )
  6. def main():
  7. sockets = []
  8. while True:
  9. try:
  10. s = socket(AF_INET, SOCK_STREAM)
  11. sockets.append(s)
  12. except OSError as exc:
  13. print('error no: %s' % (exc.errno,))
  14. print('error string: %s' % (exc.strerror,))
  15. print('fd range: [%d, %d]' % (
  16. sockets[0].fileno(),
  17. sockets[-1].fileno(),
  18. ))
  19. break
  20. if __name__ == '__main__':
  21. main()

8 行,用一个列表来存放已创建的套接字( Python 套接字对象);第 12-13 行,循环创建套接字并追加到列表中,直到 OSError 异常(系统调用出错);第 15-16 行,打印错误码;第 18-21 行,打印首尾套接字的文件描述符。

下一步

订阅更新,获取更多学习资料,请关注我们的 微信公众号

../../_images/wechat-mp-qrcode.png小菜学编程

参考文献