Cgroup 冷冻器

cgroup 冷冻器对于批量作业管理系统很有用,该系统启动和停止任务集,以便根据系统管理员的意愿来调度机器的资源。这种程序通常用于 HPC 集群上,以调度对整个集群的访问。cgroup 冷冻器使用 cgroup 来描述要由批量作业管理系统启动/停止的任务集。它还提供了一种启动和停止组成作业的任务的方法。

cgroup 冷冻器对于检查正在运行的任务组也很有用。冷冻器允许检查点代码通过尝试强制 cgroup 中的任务进入静止状态来获取任务的一致映像。一旦任务处于静止状态,另一个任务可以遍历 /proc 或调用内核接口来收集有关静止任务的信息。如果发生可恢复的错误,可以稍后重新启动检查点的任务。这也允许通过将收集的信息复制到另一个节点并在那里重新启动任务来在集群中的节点之间迁移检查点的任务。

SIGSTOP 和 SIGCONT 序列并不总是足以停止和恢复用户空间中的任务。这两个信号都可以从我们希望冻结的任务中观察到。虽然无法捕获、阻止或忽略 SIGSTOP,但等待或 ptracing 父任务可以看到它。SIGCONT 尤其不适合,因为它可能被任务捕获。任何旨在监视 SIGSTOP 和 SIGCONT 的程序都可能因尝试使用 SIGSTOP 和 SIGCONT 来停止和恢复任务而中断。我们可以使用嵌套的 bash shell 来演示这个问题

$ echo $$
16644
$ bash
$ echo $$
16690

From a second, unrelated bash shell:
$ kill -SIGSTOP 16690
$ kill -SIGCONT 16690

<at this point 16690 exits and causes 16644 to exit too>

发生这种情况是因为 bash 可以观察到这两个信号并选择如何响应它们。

另一个捕获和响应这些信号的程序示例是 gdb。实际上,任何设计为使用 ptrace 的程序都可能在此停止和恢复任务的方法上出现问题。

相比之下,cgroup 冷冻器使用内核冷冻器代码来防止冻结/解冻周期对正在冻结的任务可见。这允许上面的 bash 示例和 gdb 按预期运行。

cgroup 冷冻器是分层的。冻结 cgroup 会冻结属于该 cgroup 及其所有后代 cgroup 的所有任务。每个 cgroup 都有自己的状态(自身状态)和从父级继承的状态(父级状态)。如果两种状态均为 THAWED,则 cgroup 为 THAWED。

以下 cgroupfs 文件由 cgroup 冷冻器创建。

  • freezer.state:读写。

    读取时,返回 cgroup 的有效状态 - “THAWED”、“FREEZING” 或 “FROZEN”。这是自身状态和父级状态的组合。如果任何一个正在冻结,则 cgroup 正在冻结(FREEZING 或 FROZEN)。

    当属于 cgroup 及其后代的所有任务都被冻结时,FREEZING cgroup 会转换为 FROZEN 状态。请注意,在向 cgroup 或其后代 cgroup 添加新任务之后,cgroup 会从 FROZEN 恢复为 FREEZING,直到新任务被冻结。

    写入时,设置 cgroup 的自身状态。允许两个值 - “FROZEN” 和 “THAWED”。如果写入 FROZEN,则 cgroup(如果尚未冻结)将与其所有后代 cgroup 一起进入 FREEZING 状态。

    如果写入 THAWED,则 cgroup 的自身状态将更改为 THAWED。请注意,如果父级状态仍在冻结,则有效状态可能不会更改为 THAWED。如果 cgroup 的有效状态变为 THAWED,则因 cgroup 而冻结的所有后代也会离开冻结状态。

  • freezer.self_freezing:只读。

    显示自身状态。如果自身状态为 THAWED,则为 0;否则为 1。仅当上次写入 freezer.state 的内容为 “FROZEN” 时,此值才为 1。

  • freezer.parent_freezing:只读。

    显示父级状态。如果 cgroup 的祖先均未被冻结,则为 0;否则为 1。

根 cgroup 是不可冻结的,并且以上接口文件不存在。

  • 使用示例

    # mkdir /sys/fs/cgroup/freezer
    # mount -t cgroup -ofreezer freezer /sys/fs/cgroup/freezer
    # mkdir /sys/fs/cgroup/freezer/0
    # echo $some_pid > /sys/fs/cgroup/freezer/0/tasks
    

获取冷冻器子系统的状态

# cat /sys/fs/cgroup/freezer/0/freezer.state
THAWED

冻结容器中的所有任务

# echo FROZEN > /sys/fs/cgroup/freezer/0/freezer.state
# cat /sys/fs/cgroup/freezer/0/freezer.state
FREEZING
# cat /sys/fs/cgroup/freezer/0/freezer.state
FROZEN

解冻容器中的所有任务

# echo THAWED > /sys/fs/cgroup/freezer/0/freezer.state
# cat /sys/fs/cgroup/freezer/0/freezer.state
THAWED

这是基本机制,它应该在简单场景中为用户空间任务做正确的事情。