> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/di-27-zhang-an-quan/di-27.3-jie-zi-yuan-xian-zhi.md).

# 27.3 资源限制

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

## 资源限制

在 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 级精细约束
```

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

### 资源类型

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`）                |

**资源类型表**

### 配置登录类别

传统方法中，登录类别及其关联的资源限制定义在 **/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** 后，用户需注销并重新登录才能使更改生效。

## 启用和配置资源限制

`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 为系统设置规则。

规则语法含 **主语**（`process`、`user`、`loginclass` 或 `jail`）、主语-id、资源与动作四部分：

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

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

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

省略时默认与主语一致。

常见可用动作：

| 动作         | 说明                                                        |
| ---------- | --------------------------------------------------------- |
| `deny`     | 拒绝该资源分配或操作。                                               |
| `log`      | 不阻止操作，仅在控制台记录警告信息。                                        |
| `devctl`   | 向 devd(8) 发送事件通知，由系统设备守护进程处理。                             |
| `sig*`     | 向违规进程发送信号（如 `sigterm`、`sigkill` 等）。                       |
| `throttle` | 减慢进程执行速度；仅支持 `readbps`、`writebps`、`readiops`、`writeiops`。 |

```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
```

## 课后习题

1. 在 **/etc/login.conf** 文件中为一个测试用户类设置 `maxproc` 为 50，随后编写一个简单的 Shell 脚本在该类用户下创建超过 50 个子进程，观察系统行为，并分析内核通过何种机制阻止超限。
2. 使用 `limits -a` 查看当前 Shell 的所有资源限制，将这些限制与 `sysctl kern.maxproc` 的输出进行对比，指出用户级限制与系统全局上限之间的关系。
3. 已知 fork 炸弹 `:(){ :|:& };:` 可能拖垮未做限制的系统。请设计实验方案防止此类问题。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/di-27-zhang-an-quan/di-27.3-jie-zi-yuan-xian-zhi.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
