让坏程序、坏设备和失败路径只能局部破坏,不能拖垮整台机器。
| 资源 | 失控方式 | 被迫设计 |
|---|---|---|
| 进程槽 | 无限创建子进程 | 每用户 / 每进程树进程数上限 |
| 内存页 | 无限 malloc 或 mmap | 地址空间和物理页限额 |
| fd | 不断 open / socket 不 close | 每进程 fd 上限 |
| 磁盘块 | 写满文件系统 | 配额、预留空间、写入失败语义 |
| CPU 时间 | 死循环消耗计算资源 | 时间片、优先级、CPU 配额 |
| 网络缓冲 | 连接和收包占满内存 | 连接数、缓冲区、背压和丢弃策略 |
| 对象 | 字段 | 负责什么 |
|---|---|---|
ResourceLimits | max_processes、max_memory、max_fds、max_sockets | 定义上限 |
ResourceUsage | processes、pages、fds、sockets、cpu_ticks | 记录当前占用 |
Owner | uid、pid、process_group | 资源归属 |
CleanupList | allocated_pages、open_files、locks、children | 失败或退出时释放资源 |
FailureRecord | type、owner、resource、action | 记录失败和处理结果 |
| 失败点 | 必须释放什么 | 不能留下什么 |
|---|---|---|
| 分配进程槽后加载失败 | 进程槽、页、fd、计数 | 半初始化进程 |
| 写文件空间不足 | 已分配但未提交的数据块 | 坏 inode 或坏目录项 |
| socket 建立中断 | socket 对象、端口表占用、缓冲区 | 占住端口的幽灵连接 |
| 驱动返回错误 | 等待队列、IO 请求对象 | 永远 blocked 的进程 |
| 失败 | 恢复动作 | 验收问题 |
|---|---|---|
| 进程崩溃 | 关闭 fd、释放页、唤醒父进程 | 资源是否全部回收 |
| 内存耗尽 | 拒绝新分配,保留内核预留页 | 内核是否还能继续处理错误 |
| 磁盘写一半 | journal recovery | 重启后元数据是否一致 |
| 设备错误 | 返回错误码,重置设备或隔离请求 | 等待进程是否被唤醒 |
| 网络缓冲爆满 | 丢弃、背压或拒绝连接 | 是否只影响相关 socket |
| 实验 | 通过标准 | 证明了什么 |
|---|---|---|
| fork bomb | 超过进程上限后返回错误,shell 仍可用 | 进程限额成立 |
| fd 泄漏 | 超过 fd 上限后 open 失败,其他进程不受影响 | fd 账本成立 |
| 内存耗尽 | 用户分配失败,但内核仍能调度和打印错误 | 内核预留和失败路径成立 |
| 磁盘满 | write 返回错误,不产生坏目录项 | 文件系统失败语义成立 |
| 崩溃清理 | 进程崩溃后 fd、页、锁全部释放 | cleanup list 成立 |