简介在多核乃至众核 Linux 服务器、嵌入式多核工业主控、车载域控制器等硬件架构普及的当下单 CPU 内核调度逻辑已经无法满足整机算力调度需求。内核为了实现跨核心任务分发、算力负载均衡、异构核调度隔离、NUMA 架构内存亲和性调度设计出调度域 (Scheduling Domain)与调度组 (Scheduling Group)双层层级管理架构。其中struct sched_group作为调度域内部最核心的管理单元专门用于抽象划分调度域下的 CPU 物理核心子集依托组内 CPU 数量、调度权重、算力容量、负载统计等核心字段为内核负载均衡算法提供精准的数据依据彻底解决多核场景下任务扎堆拥堵、空闲核心算力闲置、跨核调度开销过大、实时任务调度紊乱等一系列线上生产环境常见问题。从实际工程落地层面来讲服务器集群算力调度、嵌入式多核实时系统任务分片、云计算虚拟机 CPU 亲和性绑定、工控系统软硬实时核隔离部署全都依赖调度组完成底层 CPU 资源划分与负载决策。对于底层内核开发工程师、嵌入式 Linux 研发、服务器性能调优工程师、实时操作系统架构设计者而言吃透sched_group结构体成员含义、层级组织方式、负载统计逻辑、均衡触发判定规则是掌握 Linux 多核负载均衡体系、优化整机调度吞吐量、降低跨核调度延迟、定制 CPU 资源隔离策略的核心前提。同时该部分源码也是撰写内核调度相关论文、技术调研报告、内核裁剪定制方案不可或缺的核心知识点本文将以一线底层开发工程师实战视角从理论概念、环境搭建、源码拆解、实操验证、问题排查全维度完成讲解。一、核心概念与专业术语解析1.1 调度域 Scheduling Domain调度域是 Linux 内核划分 CPU 拓扑结构的最高层级调度单元内核依据 CPU 物理拓扑、NUMA 节点、CPU 物理封装、CPU 核心层级自上而下划分多层调度域。 常见层级划分NUMA 节点域 物理 CPU 封装域 CPU 核心簇域 单核调度域。 同一调度域内的 CPU 核心具备调度互通、负载互相迁移的权限不同层级调度域定义不同的负载均衡粒度与均衡触发阈值。1.2 调度组 struct sched_group调度组是隶属于调度域内部的 CPU 资源子集一个调度域可以切分为一个或者多个调度组每一个sched_group结构体代表一组逻辑绑定的 CPU 集合。 内核将物理 CPU 核心按照业务需求、硬件拓扑划分为不同调度组后续所有负载计算、空闲算力统计、任务迁移决策均以调度组为最小统计单位而非直接遍历所有 CPU极大缩减负载均衡运算量。1.3 核心关键字段释义1.3.1 基础结构体源码定义内核 6.1/5.15 通用// 路径kernel/sched/sched.h struct sched_group { /* 指向下一个同层级调度组实现调度组链表串联 */ struct sched_group *next; /* 该调度组包含的CPU掩码精准标记组内所有CPU编号 */ struct cpumask cpumask; /* 调度组权重代表本组整体调度优先级与算力占比 */ unsigned int group_weight; /* 调度组算力容量表征本组CPU最大可承载任务负载上限 */ unsigned int group_capacity; /* 调度组当前实时负载值内核周期统计更新 */ unsigned long group_load; /* 调度组内空闲CPU数量快速判定本组是否存在空闲算力 */ int nr_idle_cpus; /* 调度组内总CPU数量 */ int group_size; /* 调度组均衡偏移阈值用于判定是否触发组间任务迁移 */ int imbalance_offset; /* 预留扩展字段用于实时调度、能耗调度扩展 */ struct sched_group_ext *ext; };逐字段实战释义next同调度域下所有调度组依靠该指针形成单向循环链表内核遍历所有分组仅需遍历链表即可无需遍历全局 CPUcpumaskCPU 位图是调度组绑定物理核心的核心标识例如0-3号CPU划为一组位图内对应位置置 1group_weight组调度权重权重越高在负载均衡过程中越容易被分配新任务常用于大小核架构调度优先级区分group_capacity组最大承载容量结合 CPU 算力主频、核数计算得出限制本组任务最大负载上限避免算力溢出group_load实时累计负载统计组内所有就绪任务总权重负载是均衡决策最核心数据源nr_idle_cpus组内空闲核心统计快速筛选空闲分组跳过高负载分组提升均衡效率group_size组内 CPU 总个数用于负载均值计算。1.4 调度组与调度域层级关系一个调度域 多个调度组组成调度域负责定义均衡策略、均衡周期、迁移延迟等全局规则调度组负责统计本组负载、空闲状态、算力资源向上为调度域提供决策数据负载均衡完整流程调度域触发均衡检查 → 遍历域内所有调度组 → 对比各组负载与空闲状态 → 高负载组向低负载 / 空闲组迁移就绪任务。1.5 负载均衡核心判定逻辑内核依靠sched_group三大核心数据完成均衡决策对比group_load识别高负载调度组与轻负载调度组查看nr_idle_cpus优先向存在空闲 CPU 的调度组迁移任务参考group_capacity避免向达到算力上限的调度组派发任务 最终实现多核 CPU 之间负载均匀分布杜绝部分核心跑满、部分核心休眠的资源浪费现象。二、环境准备2.1 软硬件环境配置标准环境类别详细配置要求操作系统Ubuntu 20.04 / Ubuntu 22.04 64 位服务器版内核版本Linux 5.15 LTS、Linux 6.1 LTS主流工业与服务器稳定内核调度组源码无大幅改动硬件平台x86_64 多核 CPU推荐 4 核 8 核 16 核支持 CPU 拓扑层级划分具备 NUMA 架构更佳编译依赖gcc 9.0、make、libncurses-dev、bison、flex、libelf-dev调试工具ftrace、perf、trace-cmd、gdb、sysfs 拓扑查看工具、cpuset 工具辅助工具htop、mpstat、taskset用于实时观测 CPU 负载与任务绑定状态2.2 内核源码获取与编译配置2.2.1 一键安装编译依赖sudo apt update -y sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev -y作用补齐内核编译、配置、模块构建全部依赖包避免编译报错中断。2.2.2 下载稳定版内核源码# 下载Linux6.1长期支持内核 wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.tar.xz # 解压源码包 tar -xf linux-6.1.tar.xz cd linux-6.12.2.3 开启调度域与调度组调试配置# 继承当前系统内核默认配置 cp /boot/config-$(uname -r) .config # 可视化内核配置界面 make menuconfig必须开启以下核心配置项否则无法调试查看调度组运行逻辑CONFIG_SCHED_SMTy # 开启超线程调度拓扑划分 CONFIG_SCHED_MCy # 开启多核CPU核心调度分组 CONFIG_NUMAy # 开启NUMA架构调度域分组多节点服务器必备 CONFIG_DEBUG_KERNELy # 内核全局调试开关 CONFIG_SCHED_DEBUGy # 调度子系统专属调试接口 CONFIG_FTRACEy # 函数跟踪跟踪调度组负载更新函数 CONFIG_CPUMASK_OFFSTACKy # 优化CPU掩码存储适配大批量分组管理保存配置退出开始编译内核# 多线程编译利用全部CPU核心加速编译 make -j$(nproc) # 安装内核模块 sudo make modules_install # 安装新内核镜像 sudo make install # 更新系统启动引导项 sudo update-grub重启服务器在启动项中选择新编译完成的内核进入实验环境。2.3 核心源码路径定位kernel/sched/sched.h # sched_group、sched_domain结构体定义 kernel/sched/topology.c # CPU拓扑构建、调度域与调度组初始化创建 kernel/sched/fair.c # 调度组负载统计、组间任务均衡迁移逻辑 kernel/sched/debug.c # 调度组调试信息导出接口三、实际应用场景300 字精准阐述调度组 CPU 集合管理机制广泛落地于各类多核 Linux 工程场景。在云计算服务器虚拟化场景中运维人员借助调度组将物理机 CPU 划分为多个独立分组不同虚拟机绑定专属调度组实现租户 CPU 资源隔离避免业务之间互相抢占算力。在车载多核域控制器场景下研发人员划分实时调度组与非实时调度组自动驾驶感知、决策等高优先级实时任务划入高权重调度组中控娱乐、多媒体进程划入普通调度组依靠组权重保障实时任务优先调度。在大型分布式工控系统中多核心主控依托调度组完成任务分片分发将采集、运算、控制业务拆分至不同 CPU 分组提升整机并发处理能力。同时在服务器性能调优场景下运维通过调整调度组容量与均衡阈值优化数据库、中间件进程的跨核调度策略有效降低 CPU 上下文切换开销大幅提升高并发业务场景下系统运行稳定性与整体吞吐性能。四、实战案例与完整代码实操4.1 查看系统原生 CPU 调度分组拓扑信息4.1.1 查看全局 CPU 拓扑层级# 查看CPU物理核心拓扑结构 cat /proc/cpuinfo | grep -E processor|core id|physical id # 查看系统NUMA节点与CPU绑定关系 numactl --hardware使用场景确认物理硬件原生 CPU 分组结构对照内核初始化生成的调度组划分规则。4.1.2 通过 sysfs 查看调度域与调度组信息# 进入调度拓扑调试目录 cd /sys/devices/system/cpu/sched_domain/ # 查看单个CPU对应的调度域层级与所属调度组 ls -l cat cpu0/domain*/group/*作用直观读取内核自动划分的调度组 CPU 掩码、组内核心数量、默认负载阈值等原生参数。4.2 内核源码调度组初始化创建流程代码内核在系统启动阶段依据 CPU 物理拓扑自动创建sched_group分组核心实现代码如下// kernel/sched/topology.c /* 依据CPU掩码创建调度组并初始化核心参数 */ static struct sched_group * build_sched_group(struct cpumask *cpu_mask, int group_weight) { struct sched_group *sg; int cpu_num; // 分配调度组内存空间 sg kzalloc(sizeof(struct sched_group), GFP_KERNEL); if (!sg) return NULL; // 绑定当前分组对应的CPU位图 cpumask_copy(sg-cpumask, cpu_mask); // 统计组内CPU总数量 sg-group_size cpumask_weight(cpu_mask); // 设置调度组调度权重 sg-group_weight group_weight; // 初始化组算力容量默认与CPU数量成正比 sg-group_capacity sg-group_size * SCHED_CPU_CAP_BASE; // 初始化负载与空闲核心计数 sg-group_load 0; sg-nr_idle_cpus 0; sg-imbalance_offset 0; // 链表指针初始化为空 sg-next NULL; return sg; }代码详细注释kzalloc内核内存分配函数申请调度组结构体内存并清零初始化cpumask_copy将传入的 CPU 核心掩码绑定至当前调度组确定分组管辖范围cpumask_weight自动统计掩码内有效 CPU 个数赋值给group_size批量初始化权重、容量、负载、空闲核心等业务字段完成调度组基础配置该函数为内核底层通用创建接口自动分组、手动自定义分组均会调用此接口。4.3 调度组负载实时统计核心源码内核定时扫描组内任务更新sched_group负载数值为均衡决策提供数据// kernel/sched/fair.c /* 周期更新指定调度组整体负载信息 */ void update_sg_group_load(struct sched_group *sg) { int cpu; unsigned long total_load 0; int idle_cnt 0; // 遍历当前调度组内所有CPU核心 for_each_cpu(cpu, sg-cpumask) { struct rq *rq cpu_rq(cpu); // 累加单个CPU运行队列负载至组总负载 total_load rq-load.weight; // 统计空闲CPU核心数量 if (rq-nr_running 0) idle_cnt; } // 刷新调度组全局负载 sg-group_load total_load; // 刷新组内空闲核心计数 sg-nr_idle_cpus idle_cnt; }代码作用遍历调度组绑定的所有 CPU 运行队列汇总所有 CPU 就绪任务总权重负载更新group_load统计无运行任务的空闲核心赋值nr_idle_cpus内核负载均衡定时器周期调用该函数保证负载数据实时有效。4.4 组间负载均衡判定逻辑代码// kernel/sched/fair.c /* 判定两个调度组之间是否需要执行任务迁移 */ static int sg_need_balance(struct sched_group *src_sg, struct sched_group *dst_sg) { unsigned long src_avg_load, dst_avg_load; // 计算源分组单CPU平均负载 src_avg_load src_sg-group_load / src_sg-group_size; // 计算目标分组单CPU平均负载 dst_avg_load dst_sg-group_load / dst_sg-group_size; // 负载差值超过阈值且目标组存在空闲CPU触发均衡迁移 if ((src_avg_load dst_avg_load src_sg-imbalance_offset) dst_sg-nr_idle_cpus 0) { return 1; // 需要迁移任务 } return 0; // 无需均衡 }实战使用场景内核遍历调度域内所有调度组两两调用该判定函数筛选出高负载源分组与空闲低负载目标分组执行就绪任务跨组迁移实现整机 CPU 负载拉平。4.5 用户态实操手动绑定进程至指定 CPU 调度组编写测试压力程序绑定至固定 CPU 分组观测调度组负载变化4.5.1 多核压力测试 C 语言代码#include stdio.h #include unistd.h #include pthread.h #include stdlib.h // 开启死循环占用CPU资源 void *cpu_stress(void *arg) { while(1) { // 空循环消耗CPU算力 ; } return NULL; } int main() { pthread_t tid; int i; // 创建8条压力线程占用CPU for(i 0; i 8; i) { pthread_create(tid, NULL, cpu_stress, NULL); } while(1) { sleep(1); } return 0; }编译运行命令gcc stress_test.c -o cpu_stress -lpthread # 后台运行压力程序 nohup ./cpu_stress 4.5.2 使用 taskset 绑定进程至指定 CPU 分组# 查找压力进程PID pidof cpu_stress # 将进程绑定至0-1号CPU调度组 taskset -c 0-1 进程PID # 查看CPU实时负载占用 mpstat -P ALL 1实操现象仅 0、1 号 CPU 负载拉满其余 CPU 保持空闲对应所属调度组group_load数值大幅升高其余分组负载不变完美印证调度组资源隔离特性。4.6 Ftrace 跟踪调度组核心函数调用通过内核跟踪工具实时观测调度组负载更新、均衡判定执行流程# 挂载调试文件系统 sudo mount -t debugfs none /sys/kernel/debug # 清空历史跟踪日志 echo /sys/kernel/debug/tracing/trace # 指定需要跟踪的调度组内核函数 echo update_sg_group_load /sys/kernel/debug/tracing/set_ftrace_filter echo sg_need_balance /sys/kernel/debug/tracing/set_ftrace_filter # 开启函数跟踪模式 echo function /sys/kernel/debug/tracing/current_tracer # 启动跟踪 echo 1 /sys/kernel/debug/tracing/tracing_on新开终端运行 CPU 压力程序后执行以下命令查看调用日志cat /sys/kernel/debug/tracing/trace # 关闭跟踪 echo 0 /sys/kernel/debug/tracing/tracing_on实战价值直观查看调度组负载更新频率、均衡判定触发时机验证源码逻辑与系统实际运行流程完全一致。五、常见问题与实战答疑Q1系统开机后调度组划分混乱和物理 CPU 拓扑不匹配如何解决解答首先检查是否关闭CONFIG_SCHED_MC多核调度拓扑配置未开启则内核无法按照物理核心划分分组其次关闭 BIOS 内异常超线程、CPU 节能聚合功能重启系统重新初始化调度域与调度组最后通过topology.c源码调试打印 CPU 层级信息手动修正拓扑识别异常问题。Q2调度组 group_load 负载数值更新延迟负载均衡调度不及时解答该问题大多为内核负载均衡扫描周期设置过大导致可修改内核调度均衡滴答时钟周期缩短调度组负载统计间隔同时检查是否开启 CPU 节能降频策略节能模式会抑制跨组任务迁移关闭节能策略即可恢复正常均衡效率。Q3手动划分自定义调度组之后进程无法跨组迁移解答自定义调度组必须隶属于同一个调度域不同调度域下的调度组默认关闭任务迁移权限其次检查调度组imbalance_offset均衡偏移阈值设置过大导致负载差值无法达到触发条件适当调低阈值即可恢复跨组迁移能力。Q4NUMA 多节点服务器中跨节点调度组负载均衡性能极差解答NUMA 架构下跨节点内存访问延迟极高内核默认限制跨节点调度组任务迁移频率工程最佳方案为同 NUMA 节点内划分调度组尽量避免任务跨节点调度组迁移减少远程内存访问带来的性能损耗。Q5修改 sched_group 结构体字段后内核编译报错解答修改调度组结构体后必须完整重新编译内核而非仅编译模块同时同步修改topology.c、fair.c中所有引用该结构体的业务逻辑代码保证字段调用统一避免结构体成员不匹配引发内核 Oops 崩溃。六、实践建议与工程最佳实践嵌入式多核系统分组最佳实践嵌入式工控、车载系统建议采用功能隔离式调度组划分将实时控制业务划入高权重调度组后台日志、升级、运维进程划入低权重分组依靠group_weight权重字段保障实时业务调度优先级杜绝非核心进程抢占算力。服务器性能调优调度组优化技巧高并发数据库、缓存服务器场景下合理拆分调度组规模单个调度组内 CPU 数量控制在 4~8 核为宜分组过小会增加均衡调度开销分组过大容易出现内部负载不均同时调高业务核心调度组group_capacity算力上限保障核心业务算力充足。内核调试排错规范排查多核调度卡顿、负载失衡问题时排查顺序固定为查看调度组 CPU 掩码绑定状态 → 观测group_load负载统计是否正常 → 验证空闲核心nr_idle_cpus统计准确性 → 最后核查均衡判定阈值与迁移策略快速定位问题根因。内核二次开发定制建议进行调度策略二次开发时尽量不要删减sched_group基础核心字段可通过ext扩展指针新增自定义调度属性基于原有负载统计、均衡决策逻辑做功能扩展兼容内核原生调度框架大幅降低内核版本迭代适配成本。容器虚拟化场景资源隔离方案K8s、Docker 容器环境中直接依托内核调度组实现 CPU 资源硬隔离将容器进程限定在专属调度组范围内运行相比传统 CPU 使用率限制更加稳定彻底解决容器之间算力互相抢占的线上故障。七、全文总结与工程延伸应用本文从行业实际需求出发完整梳理了 Linux 内核调度组 sched_group整体技术体系从基础理论概念、实验环境搭建、CPU 拓扑结构解析、结构体字段深度拆解再到内核初始化源码、负载统计源码、均衡判定源码逐层剖析搭配用户态压力测试、CPU 绑定实操、ftrace 内核函数跟踪等实战案例全方位讲清调度组作为调度域 CPU 集合管理单元的核心工作原理。调度组本质是 Linux 内核为适配多核硬件架构设计的分层算力资源管理容器依靠 CPU 掩码完成物理核心绑定依托权重、容量、实时负载、空闲核心等统计字段简化多核负载均衡运算复杂度让内核无需遍历全局所有 CPU仅通过分组聚合数据即可高效完成任务调度与算力分发是 Linux 从单核调度走向多核众核调度架构升级的核心基石。在当下工业实时控制系统、自动驾驶车载系统、云计算虚拟化集群、大型互联网服务器集群等主流技术场景中调度组 CPU 集合管理机制都承担着底层资源调度的核心作用。建议各位底层研发与运维工程师结合本文提供的内核源码与实操命令自行修改调度组权重、均衡阈值等参数进行对比实验观测不同参数下整机调度延迟、CPU 负载均衡度、进程响应速度的变化规律真正做到吃透底层调度原理将调度组相关技术落地到实际项目性能优化、内核定制开发、实时系统架构搭建等真实业务场景中。