Skip to content

27.3 资源限制

FreeBSD 提供 /etc/login.conf 静态资源限制与 rctl 动态资源限制两种机制。本节分别给出登录类别(login class)配置方法和进程级约束规则定义。

27.3.1 资源限制

在 FreeBSD 中,资源限制指控制与管理进程和用户可使用的系统资源的机制,用于防止单个进程或用户消耗过多资源,避免性能下降或系统不稳定。资源限制有助于确保系统中所有活动进程和用户间的资源公平分配。

FreeBSD 提供多种方法供管理员限制用户可使用的系统资源量。

传统方法是通过编辑 /etc/login.conf 文件来定义登录类别。虽然该方法仍受支持,但任何更改都需经过多个步骤:编辑该文件、重建资源数据库、修改 /etc/master.passwd 文件,以及重建密码数据库。这一过程繁琐,耗时取决于需配置的用户数量。

与之相比,rctl 提供了一种更细粒度的资源限制机制,它还可为进程和 Jail 设置资源约束。

sh
两种资源限制机制对比:

  传统静态限制(/etc/login.conf)

  编辑 login.conf
  cap_mkdb 重建数据库
  chpass 修改用户类别
  用户重新登录生效

  按登录类别(login class)限制

  特点:
  - 静态配置,重启后保持
  - 粒度为登录类别
  - 无法限制 jail
  - 无法限制 I/O 速率

  适用场景:按用户类别统一配置

  动态资源限制(rctl)

  loader.conf 启用 kern.racct.enable=1
  rctl -a 添加规则(即时生效)
  /etc/rctl.conf 持久化

  按主语(process/user/loginclass/jail)限制

  特点:
  - 动态调整,无需重启
  - 粒度精细至单个进程
  - 可限制 jail
  - 可限制 I/O 速率、线程数

  适用场景:进程级、jail 级精细约束

本节演示两种控制资源的方法,从传统方法开始。

27.3.1.1 资源类型

FreeBSD 支持对以下资源类型施加限制:

类型描述
cputime限制进程可消耗的 CPU 时间量
memoryuse / memorylocked控制进程可使用的物理内存量 / 锁定内存量
openfiles限制进程可同时打开的文件数量
maxproc控制用户或进程可创建的进程数量
filesize限制进程可创建的文件的最大大小(仅 login.conf)
coredumpsize控制是否允许进程生成核心转储文件及其大小
datasize / stacksize限制数据段 / 栈段大小
vmemoryuse限制进程的总虚拟存储器使用量
sbsize限制套接字缓冲区大小(仅 login.conf)
pseudoterminals限制伪终端数量
swapuse限制交换空间使用量
umtxp限制进程共享 pthread 锁的最大数量(仅 login.conf)
pipebuf限制管道缓冲区的最大大小(仅 login.conf)
nthr限制线程数(仅 rctl
wallclock / pcpu限制墙钟时间 / CPU 百分比(仅 rctl
readbps / writebps / readiops / writeiops限制文件系统读写速率(仅 rctl

资源类型表

27.3.1.2 配置登录类别

传统方法中,登录类别及其关联的资源限制定义在 /etc/login.conf 文件中。每个用户账户可归入某个登录类别,default 为默认类别。各类别关联一组登录能力(login capability),格式为 名称=值 对,其中 名称 是已知标识符, 为任意字符串,按对应 名称 的规则处理。

sh
login.conf 配置流程:

  编辑 /etc/login.conf

  定义用户类别(如 limited)
  设置资源限制参数(如 :maxproc=50:)
  通过 :tc=default: 继承默认设置


  运行 cap_mkdb /etc/login.conf

  将文本配置编译为数据库(login.conf.db)


  使用 chpass 将用户归入指定类别

  chpass ykla Class 字段设为 limited


  用户注销并重新登录

  新登录会话继承 limited 类别的资源限制


  限制生效(maxproc=50 等)

配置资源限制须先编辑 /etc/login.conf 文件,定位至拟修改的用户类别节。

本例假设所用类别名为 limited,若不存在则创建。

ini
limited:\	# 用户类别名称
        :maxproc=50:\ # 将 limited 类别下用户的最大进程数(maxproc)设为 50
        :tc=default: # 此用户类别继承 default 类别的默认设置

修改 /etc/login.conf 后,运行 cap_mkdb 生成数据库,供 FreeBSD 应用这些设置:

sh
# cap_mkdb /etc/login.conf

chpass 可为目标用户 ykla 切换类别:

sh
# chpass ykla

技巧

使用命令 export EDITOR=ee 可将默认编辑器由 vi 变更为 ee,便于操作。

这将打开文本编辑器,按如下方式添加新的 limited 类别:

ini
#Changing user information for ykla.
Login: ykla
Password: $6$SqMJXrv5aC6Wq.by$nmbZs078aHNBVyh9noLFouJsGHyFSvQIzH0W4zpdfXuPtGtt.FHgWfXDHVBa
Uid [#]: 1001
Gid [# or name]: 1001
Change [month day year]:
Expire [month day year]: April 16, 2027
Class: limited
Home directory: /home/ykla
Shell: /bin/sh
Full Name: User &
Office Location:
Office Phone:
Home Phone:
Other information:

现在归属于 limited 类别的用户,其最大进程数将限制为 50。注意,以上仅为使用 /etc/login.conf 设置资源限制的一个示例。

修改 /etc/login.conf 后,用户需注销并重新登录才能使更改生效。

27.3.2 启用和配置资源限制

rctl 命令用于控制资源限制,可动态分配资源约束至特定进程或用户,与所属用户类别无关。

使用 rctl 前需先将其启用,在 /boot/loader.conf 中添加以下行并重启系统:

ini
kern.racct.enable=1

内核可调参数 kern.racct.enable=1 即启用了 rctl 功能。此外,若在 /etc/rctl.conf 中预定义了持久化规则,可执行以下命令使其在启动时自动加载:

sh
# service rctl enable
# service rctl start

/etc/rctl.conf 为空,则 service rctl start 无实际效果。

此后即可使用 rctl 为系统设置规则。

规则语法含 主语processuserloginclassjail)、主语-id、资源与动作四部分:

sh
主语:主语-id:资源:动作=数量/对象

其中 对象 定义数量统计范围:

标识路径作用范围说明
/process每进程对单个进程分别应用资源限制。
/user每用户对同一用户的所有进程统一限制。
/loginclass每登录类别按登录类别(login class)分组限制。
/jail每 Jail按 Jail 分组限制。

省略时默认与主语一致。

常见可用动作:

动作说明
deny拒绝该资源分配或操作。
log不阻止操作,仅在控制台记录警告信息。
devctl向 devd(8) 发送事件通知,由系统设备守护进程处理。
sig*向违规进程发送信号(如 sigtermsigkill 等)。
throttle减慢进程执行速度;仅支持 readbpswritebpsreadiopswriteiops
sh
rctl 规则语法分解:

  主语:主语-id:资源:动作=数量/对象

    └── 统计范围(/process、/user、/loginclass、/jail)

    └── 数量(整数,如 10)

    └── 动作(deny、log、devctl、sigterm、sigkill、throttle)

      └── 资源(maxproc、openfiles、vmemoryuse、readbps 等)

      └── 主语-id(用户名、UID、进程 ID、jail 名称、登录类别名)

   └── 主语(process、user、loginclass、jail)

  示例:user:ykla:maxproc:deny=10/user

  └── 统计范围:按用户
   └── 数量:10
       └── 动作:拒绝
     └── 资源:最大进程数
    └── 主语-id:用户名 ykla
         └── 主语:按用户

例如,要约束用户 ykla 最多只能创建 10 个进程,可执行:

sh
# rctl -a user:ykla:maxproc:deny=10/user

要检查已应用的资源限制,执行 rctl:

sh
# rctl

输出应类似于以下内容:

sh
user:ykla:maxproc:deny=10

将规则写入 /etc/rctl.conf 文件,重启后仍可生效。格式为单条规则,无需前导命令。例如,前述规则可添加为:

ini
user:ykla:maxproc:deny=10

27.3.3 课后习题

  1. /etc/login.conf 文件中为一个测试用户类设置 maxproc 为 50,随后编写一个简单的 Shell 脚本在该类用户下创建超过 50 个子进程,观察系统行为,并分析内核通过何种机制阻止超限。

  2. 使用 limits -a 查看当前 Shell 的所有资源限制,将这些限制与 sysctl kern.maxproc 的输出进行对比,指出用户级限制与系统全局上限之间的关系。

  3. 已知 fork 炸弹 :(){ :|:& };: 可能拖垮未做限制的系统。请设计实验方案防止此类问题。