调度器之任务分组

任务分组

我们先看以下两种场景。

(1)执行<font style="color:rgb(0,0,0);">make -j10</font>(选项<font style="color:rgb(0,0,0);">-j10</font>表示同时执行 10 条命令),编译 Linux 内核,同时运行视频播放器,如果给每个进程平均分配 CPU 时间,会导致视频播放很卡。

(2)用户 1 启动 100 个进程,用户 2 启动 1 个进程,如果给每个进程平均分配 CPU 时 间,用户 2 的进程只能得到不到 1%的 CPU 时间,用户 2 的体验很差。

怎么解决呢?把进程分组。对于第一种场景,把编译 Linux 内核的所有进程放在一个任务组 中,把视频播放器放在另一个任务组中,给两个任务组分别分配 50%的 CPU 时间。对于第二种场景,给用户 1 和用户 2 分别创建一个任务组,给两个任务组分别分配 50%的 CPU 时间。


任务分组(Task Group) 是对进程进行逻辑划分和资源限制管理的一种机制,主要用于 控制资源使用、调度策略、统计 等目的。

任务分组的实现核心是 cgroup(Control Groups)子系统,以及调度器中的 task_group 结构体

struct task_group

/* task group related information */
struct task_group {
	struct cgroup_subsys_state css;

#ifdef CONFIG_FAIR_GROUP_SCHED
	/* schedulable entities of this group on each cpu */
	struct sched_entity **se;
	/* runqueue "owned" by this group on each cpu */
	struct cfs_rq **cfs_rq;
	unsigned long shares;
#endif

#ifdef CONFIG_RT_GROUP_SCHED
	struct sched_rt_entity **rt_se;
	struct rt_rq **rt_rq;

	struct rt_bandwidth rt_bandwidth;
#endif
    ...
};
    
  • 每个 task_group 表示一个进程组。
  • 每个 task_group 对应一个调度实体数组(se)和一个运行队列(cfs_rq)等。
  • task_groupcgroup 是一一对应的(由 css 连接)。
  • 每个进程的 task_struct 中会关联其所属的 task_group

调度器中的任务分组支持

Linux 支持多个调度器,比如:

  • CFS(完全公平调度器)
  • RT(实时调度器)

每种调度器都有对应的 task group 处理逻辑,例如:

  • cfs_rq:表示该 task_group 的 CFS 调度运行队列。
  • rt_rq:表示该 task_group 的实时调度运行队列。
  • 对每个 CPU,调度器会在其上为每个 task_group 创建对应的运行队列。

调度时,内核会根据任务所属的 group,在其 group 的运行队列中进行选择,这样可以实现任务分组的公平调度和资源限制。


CPU运行队列和task_group中运行队列的关系

CPU 的运行队列(per-CPU runqueue)

每个 CPU 上维护一个独立的运行队列:

struct rq {
    struct cfs_rq cfs;  // 默认调度器 CFS 的运行队列
    struct rt_rq rt;    // 实时调度器的运行队列
    ...
    };

这个 rq 是每个 CPU 的调度核心数据结构,调度器总是在该 CPU 的 rq 上操作任务。


task_group 的运行队列(per-task_group runqueue)

task_group 的核心在于它为 每个 CPU 创建自己的调度子队列,例如:

struct task_group {
    struct cfs_rq **cfs_rq;         // 所有 CPU 上本组的 CFS 队列数组
    struct sched_entity **se;       // 本组在上一级 group 中的调度实体
    ...
};
  • tg->cfs_rq[cpu] 表示该任务组在第 cpu 核心上的 CFS 运行队列。
  • tg->se[cpu] 表示该任务组在父组中代表自身的调度实体(可嵌套)。

这形成了一个分组树结构:组嵌套 -> 组调度实体 -> 组运行队列


任务组在每个处理器上有公平调度实体、公平运行队列、实时调度实体和实时运行队列,根任务组比较特殊:没有公平调度实体和实时调度实体。

(1)任务组的下级公平调度实体加入任务组的公平运行队列,任务组的公平调度实体加入上级任务组的公平运行队列。

(2)任务组的下级实时调度实体加入任务组的实时运行队列,任务组的实时调度实体 加入上级任务组的实时运行队列。


运行队列之间的关系图

以 CFS 调度器为例,关系如下图:

每个 CPU:
rq (CPU0)
├── cfs_rq                      // CPU 的根调度队列
│   ├── se (A组调度实体) ─┐
│   ├── se (B组调度实体) ─┐│
│                         ││
│                         ▼▼
│                   task_group_A.cfs_rq[CPU0]
│                   task_group_B.cfs_rq[CPU0]
  • 每个 CPU 的 rq.cfs 是顶层队列,里面的 sched_entity 可以是单个任务,也可以是一个组。
  • 如果是组的 sched_entity,就指向该组的 cfs_rq[cpu]
  • 递归结构允许 group 嵌套 group,调度器按公平调度递归下去。

调度器如何使用它们

以cfs调度器为例,调度器在进行调度选择时:

  1. 遍历 CPU 的 rq.cfs 队列,挑选最合适的 sched_entity
  2. 如果该 sched_entity 是一个任务,就直接调度
  3. 如果该 sched_entity 是一个任务组,就进入对应的 task_group.cfs_rq[cpu]
  4. 在该队列中递归选择下一级的 sched_entity,直到选出最终的任务

为什么这么设计?

这是一种典型的 分层调度(Hierarchical Scheduling) 机制,有几个优点:

  • 支持资源公平:例如,每组任务在顶层调度中获得公平份额
  • 支持资源限制:可以对每组任务设置 CPU 份额(如通过 cfs_quota_us
  • 支持嵌套组调度:适用于容器、Kubernetes pod、服务/用户分组等
  • 实现清晰:调度逻辑复用 CFS 的实体结构和算法

task_group与 cgroup 的关系

task_group 并不是用户直接使用的接口,而是内核内部与 **cgroup**** 子系统** 的绑定结构。

# 创建一个新的 CPU 资源组
mkdir /sys/fs/cgroup/cpu/mygroup

# 向其中加入任务
echo <pid> > /sys/fs/cgroup/cpu/mygroup/tasks

当进程加入某个 cgroup 后,其 task_struct 中的 task_group 指针会指向该 cgroup 对应的 task_group 实例,调度器就会按组来对其调度。


任务分组的用途

任务分组的主要作用包括:

作用说明
资源隔离可以为每组任务限制 CPU、内存、I/O 等资源
公平调度组内共享时间片,组间公平分配 CPU
负载统计按组统计 CPU、内存使用,支持审计与性能分析
服务级别管理可按服务、容器或租户分组,管理更清晰

典型应用场景

  1. Docker 容器:每个容器会被映射为一个独立的 cgroup,自然形成任务分组。
  2. 系统级任务隔离:比如将系统服务和用户应用程序分组,防止干扰。

调试与查看

可以通过以下方式查看任务所属的 task group(cgroup):

cat /proc/<pid>/cgroup

查看调度相关的任务组结构:

cat /sys/fs/cgroup/cpu/mygroup/cpu.stat

参考资料

  1. Professional Linux Kernel Architecture,Wolfgang Mauerer
  2. Linux内核深度解析,余华兵
  3. Linux设备驱动开发详解,宋宝华
  4. linux kernel 4.12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值