简介在传统 Linux 实时调度体系中SCHED_FIFO与SCHED_RR两类软实时任务具备全局高抢占特性。一旦系统内某一组实时业务持续占用 CPU同核心下其他实时进程、普通业务都会被长期阻塞极端场景下甚至引发系统 hung、关键业务超时。在多租户嵌入式设备、工业工控一体机、服务器虚拟化实时分区、车载域控多应用隔离等场景中实时 CPU 资源抢占失控是长期困扰研发与运维的痛点。为解决这一问题Linux 内核引入了RT_GROUP_SCHED组调度机制结合cgroup v1/cgroup v2实现对实时任务的 CPU 带宽配额、资源隔离与流量管控。该机制不再以单个进程为管控单元而是将一组关联实时任务划入同一个调度组通过rt_runtime_us、rt_period_us等参数硬性限制每组实时任务在单个调度周期内可使用的 CPU 时长从内核层面杜绝单个业务组垄断实时计算资源。对于嵌入式 Linux 工程师、实时系统调优人员、虚拟化平台研发、工控系统开发者而言吃透 RT 组调度的内核实现、cgroup 配置、带宽限流逻辑与故障排查方法是搭建高可靠多分区实时系统的必备技能。本文从基础概念、环境搭建、内核源码、实操案例、问题排查到工程最佳实践完整展开内容兼顾源码研读、线上落地、论文与技术报告撰写所有代码与命令均可直接复现全程以一线 Linux 内核工程师实战视角讲解避开纯理论堆砌。一、核心概念与术语解析1.1 传统 Linux 实时调度存在的缺陷Linux 标准实时调度策略分为两种SCHED_FIFO先来先服务实时调度高优先级任务一旦运行会一直占用 CPU 直至主动放弃、阻塞或被更高优先级任务抢占SCHED_RR时间片轮转实时调度同优先级任务按照固定时间片轮流执行仍具备高于普通 CFS 任务的全局抢占权。二者共同短板无带宽限制。只要任务处于就绪态就会持续抢占 CPU。在多业务混合部署场景下一组异常实时任务会直接拖垮整个系统的实时响应能力无法做到业务间资源隔离。1.2 RT_GROUP_SCHED 核心机制概述RT_GROUP_SCHED是内核编译选项开启后启用实时组调度框架核心思想将进程按业务维度划分为不同调度组task group为每个组配置独立的 CPU 实时带宽配额周期时长、最大可用 CPU 时间组内所有SCHED_FIFO/SCHED_RR任务共享本组配额耗尽带宽后本组实时任务被限流让出 CPU组与组之间相互隔离单个组异常不会影响其他实时组。该机制基于 cgroup 实现管控接口用户态通过文件系统读写即可配置带宽无需修改内核代码。1.3 关键参数定义cgroup 实时带宽在 cgroup cpu 子系统下实时调度核心管控参数单位微秒 uscpu.rt_period_us实时带宽的统计周期代表带宽计算的时间窗口全局默认通常为 1000000us1 秒。cpu.rt_runtime_us当前调度组在一个rt_period_us周期内允许所有实时任务累计占用的最大 CPU 时长。该值为 0 表示禁用本组实时任务数值不能超过rt_period_us。计算公式单组实时 CPU 最大占比 rt_runtime_us /rt_period_us × 100%举例周期 1s配额 200000us → 该组实时任务 CPU 上限为 20%。1.4 内核关键数据结构1.4.1 task_group 调度组结构体开启RT_GROUP_SCHED后内核使用struct task_group管理调度组每个 cgroup 对应一个实例// kernel/sched/sched.h struct task_group { /* CFS组调度相关成员本文省略 */ #ifdef CONFIG_RT_GROUP_SCHED /* 每个CPU对应的实时运行队列组 */ struct rt_rq **rt_rq; /* 组级别的实时带宽控制参数 */ int rt_runtime; int rt_period; /* 带宽节流、定时器、统计计数 */ struct rt_bandwidth rt_bw; #endif /* 其他信号、内存、进程链表成员省略 */ };rt_rq每个 CPU 绑定独立的实时运行队列组内实时任务挂载至此rt_runtime/rt_period对应用户态rt_runtime_us/rt_period_usrt_bandwidth实时带宽控制核心结构体包含定时器、剩余时长、限流标记。1.4.2 rt_bandwidth 带宽控制结构体// kernel/sched/rt.c struct rt_bandwidth { /* 周期定时器周期到期后重置实时带宽配额 */ struct hrtimer rt_period_timer; /* 周期定时器触发标识 */ bool timer_active; /* 本组剩余可用实时CPU时间 */ s64 rt_remaining; /* 带宽耗尽标记true表示本组实时任务被限流 */ bool throttled; };当rt_remaining递减至 0throttled置位组内所有实时任务停止调度等待下一个周期重置配额。1.5 调度流转核心流程进程加入指定 cgroup归属对应task_group进程设为SCHED_FIFO/SCHED_RR实时策略进入组内rt_rq就绪队列任务运行时内核递减本组rt_bandwidth-rt_remaining剩余时长为 0 → 触发限流组内实时任务暂停调度周期定时器到期 → 重置rt_remaining清除限流标记恢复调度。二、环境准备2.1 软硬件与版本要求分类版本 / 配置说明操作系统Ubuntu 20.04 / 22.04 64bit主流服务器 / 嵌入式发行版均可内核版本Linux 5.4、5.15、6.1 LTS企业主流长期支持版本逻辑完全兼容硬件架构x86_64推荐 4 核及以上 CPU、4G 内存多组任务压测更明显依赖工具gcc、make、libncurses-dev、bison、flex、cgroup-tools、htop、perf调试工具ftrace、trace-cmd、gdb、strace2.2 内核编译与配置开启 RT_GROUP_SCHED原生系统内核大概率未开启实时组调度需要重新编译内核启用对应开关。步骤 1安装编译依赖sudo apt update sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev cgroup-tools作用安装内核编译工具链、cgroup 操作工具与依赖库。步骤 2下载并解压内核源码# 以 Linux 5.15 LTS 为例 wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.tar.xz tar -xf linux-5.15.tar.xz cd linux-5.15步骤 3内核配置开启关键选项# 继承当前系统内核配置 cp /boot/config-$(uname -r) .config make menuconfig在图形配置界面中依次开启以下选项General setup --- [*] Control Group support # 开启cgroup基础支持 Kernel features --- [*] Group CPU scheduler # 组调度总开关 - Group CPU scheduler [*] Realtime group scheduling # CONFIG_RT_GROUP_SCHED 核心开关 [*] Enable different CONFIG_SCHED_* options --- [*] SCHED_FIFO [*] SCHED_RR # 确保传统实时调度开启 Kernel hacking --- [*] Kernel debugging [*] Function tracer # ftrace 跟踪内核函数用于调试保存配置并退出。步骤 4编译、安装内核并重启# 多核编译加速构建 make -j$(nproc) sudo make modules_install sudo make install # 更新引导项 sudo update-grub重启服务器在 GRUB 菜单选择新编译内核进入。步骤 5验证内核配置# 检查是否开启 RT_GROUP_SCHED zcat /proc/config.gz | grep RT_GROUP_SCHED输出CONFIG_RT_GROUP_SCHEDy即代表配置生效。2.3 cgroup 挂载准备本文使用cgroup v1工业实时系统最常用版本挂载 cpu 子系统# 创建cgroup根目录 sudo mkdir /sys/fs/cgroup/cpu sudo mount -t tmpfs cgroup_root /sys/fs/cgroup/cpu # 挂载cpu子系统包含实时带宽控制 sudo mount -t cgroup -o cpu none /sys/fs/cgroup/cpu作用cgroup 文件系统挂载完成后即可通过目录文件配置实时带宽。三、应用场景RT 组调度是多业务实时系统的核心隔离手段广泛落地于工业与嵌入式领域。工业工控一体机常同时运行设备控制、人机交互、日志采集三类进程将三类业务划分为独立 cgroup 组分别配置不同实时 CPU 带宽可防止高负载控制任务抢占交互界面资源保证操作响应流畅。车载域控制器中整车动力控制、多媒体娱乐、车载诊断程序分属不同实时组借助 rt_runtime_us 限制各组 CPU 上限避免娱乐进程影响行车安全类高优先级实时任务。在云边缘实时服务器场景下多租户实时音视频解码、数据采集服务通过 RT 组调度做资源切片单租户异常不会扩散至其他租户大幅提升集群整体稳定性与服务可用性。四、实际案例与步骤代码 实操本章节分为内核源码解析、用户态测试程序、cgroup 带宽配置、功能验证四部分所有代码可直接复制运行。4.1 内核源码实时带宽限流核心逻辑4.1.1 实时任务带宽扣减逻辑内核在实时任务运行时周期性扣除本组剩余 CPU 时间代码位于kernel/sched/rt.c/* * 实时任务运行时扣除对应调度组的带宽 * rq: 当前CPU运行队列 * rt_rq: 当前组的实时运行队列 * delta: 本次运行消耗的CPU时间纳秒 */ static void sched_rt_account_runtime(struct rq *rq, struct rt_rq *rt_rq, u64 delta) { struct task_group *tg rt_rq-tg; struct rt_bandwidth *rt_bw tg-rt_bw; /* 未限流则扣除剩余时间 */ if (!rt_bw-throttled) { rt_bw-rt_remaining - delta; /* 剩余时间小于等于0触发限流 */ if (rt_bw-rt_remaining 0) { rt_bw-throttled true; /* 暂停本组所有实时任务调度 */ rt_rq_throttle(rt_rq); printk(KERN_WARNING RT group bandwidth exhausted, group throttled\n); } } }代码说明每次任务运行产生时间片消耗调用该函数扣减rt_remaining带宽耗尽时置位throttled标记调用rt_rq_throttle暂停组内实时队列内核打印警告日志可通过dmesg观测限流事件。4.1.2 周期定时器重置带宽周期定时器是带宽恢复的核心每个周期结束后重置可用 CPU 时间/* 实时带宽周期定时器回调函数 */ static enum hrtimer_restart rt_period_timer(struct hrtimer *timer) { struct rt_bandwidth *rt_bw container_of(timer, struct rt_bandwidth, rt_period_timer); struct task_group *tg container_of(rt_bw, struct task_group, rt_bw); int runtime tg-rt_runtime; /* 重置剩余可用实时时间 */ rt_bw-rt_remaining runtime * NSEC_PER_USEC; /* 清除限流标记 */ rt_bw-throttled false; /* 唤醒被限流的实时队列恢复调度 */ rt_unthrottle_group(tg); /* 重新启动高精度定时器 */ hrtimer_forward_now(timer, ns_to_ktime(tg-rt_period * NSEC_PER_USEC)); return HRTIMER_RESTART; }代码说明定时器按照rt_period_us周期触发统一恢复全组带宽解除限流。4.2 编写实时压测测试程序编写一个死循环SCHED_FIFO实时任务用于占用 CPU、触发带宽限流。文件命名rt_stress.c。#include stdio.h #include stdlib.h #include unistd.h #include pthread.h #include linux/sched.h #include sys/syscall.h #define RT_PRIORITY 80 // 实时优先级范围 1~99数值越大优先级越高 /* 设置当前线程为 SCHED_FIFO 实时调度 */ int set_sched_fifo(void) { struct sched_param param; param.sched_priority RT_PRIORITY; // 设置当前线程调度策略与优先级 if (pthread_setschedparam(pthread_self(), SCHED_FIFO, param) 0) { perror(pthread_setschedparam failed); return -1; } return 0; } /* 实时负载线程死循环占用CPU */ void *rt_worker(void *arg) { set_sched_fifo(); printf(RT worker thread started, PID: %d\n, gettid()); // 纯计算负载持续占用CPU while (1) { unsigned long i; for (i 0; i 10000000; i); } return NULL; } int main(int argc, char *argv[]) { pthread_t tid; printf(Create RT stress task\n); // 创建实时负载线程 if (pthread_create(tid, NULL, rt_worker, NULL) 0) { perror(pthread_create failed); return -1; } pthread_join(tid, NULL); return 0; }代码作用创建高优先级 FIFO 实时线程无限循环占用 CPU用于模拟异常实时任务。编译命令gcc rt_stress.c -o rt_stress -lpthread4.3 创建 cgroup 分组并配置实时带宽我们创建两个独立 cgroup 组rt_group1、rt_group2做隔离对比测试。步骤 1创建 cgroup 目录cd /sys/fs/cgroup/cpu sudo mkdir rt_group1 rt_group2每个目录自动生成cpu.rt_period_us、cpu.rt_runtime_us等控制文件。步骤 2统一设置调度周期全局窗口 1 秒# 周期1000000 us 1s echo 1000000 | sudo tee rt_group1/cpu.rt_period_us echo 1000000 | sudo tee rt_group2/cpu.rt_period_us步骤 3配置差异化带宽配额# rt_group1配额 200000us → 最大20% CPU echo 200000 | sudo tee rt_group1/cpu.rt_runtime_us # rt_group2配额 500000us → 最大50% CPU echo 500000 | sudo tee rt_group2/cpu.rt_runtime_us步骤 4将测试进程加入 cgroup 组新开终端后台运行压测程序sudo ./rt_stress # 获取进程PID PID$! echo RT stress PID: $PID将 PID 加入rt_group1echo $PID | sudo tee /sys/fs/cgroup/cpu/rt_group1/cgroup.procs4.4 功能验证与观测4.4.1 查看 CPU 占用与限流状态使用htop观测 CPU 使用率htop现象进程 CPU 占用稳定在20% 左右不会占满核心证明带宽限制生效。4.4.2 查看内核限流日志dmesg -w持续观察当组内实时带宽耗尽时会打印内核警告RT group bandwidth exhausted, group throttled代表 RT 组调度已触发限流。4.4.3 跨组隔离验证再启动一个压测进程加入rt_group2sudo ./rt_stress PID2$! echo $PID2 | sudo tee /sys/fs/cgroup/cpu/rt_group2/cgroup.procs观测结果两个进程分别按照 20%、50% 配额占用 CPU互不干扰资源隔离生效。4.5 使用 ftrace 跟踪 RT 组调度内核函数跟踪带宽扣减、限流、定时器函数深入观测内核行为# 开启ftrace echo function /sys/kernel/debug/tracing/current_tracer # 设置跟踪函数 echo sched_rt_account_runtime /sys/kernel/debug/tracing/set_ftrace_filter echo rt_period_timer /sys/kernel/debug/tracing/set_ftrace_filter echo rt_rq_throttle /sys/kernel/debug/tracing/set_ftrace_filter # 开启跟踪 echo 1 /sys/kernel/debug/tracing/tracing_on # 查看跟踪日志 cat /sys/kernel/debug/tracing/trace作用可清晰看到带宽扣减、限流触发、周期重置的完整调用链路。五、常见问题与解答Q1配置完 cpu.rt_runtime_us 后实时任务依然占满 CPU限制不生效解答优先排查三点1. 内核未开启CONFIG_RT_GROUP_SCHED使用zcat /proc/config.gz验证2. 进程未正确写入对应 cgroup 的cgroup.procs3. 只配置了子组未关闭根 cgroup 的实时带宽根组默认无限制。Q2修改 cpu.rt_period_us 时报错 “Operation not permitted”解答rt_period_us属于组全局周期仅根 cgroup 可修改子 cgroup 只能修改rt_runtime_us。统一在/sys/fs/cgroup/cpu根目录配置周期即可。Q3实时任务被限流后为什么不是立即恢复而是等待固定周期解答RT 组调度采用基于周期的带宽限流算法而非令牌桶。必须等待rt_period_us定时器到期内核才会统一重置剩余 CPU 时间以此保证带宽统计的公平性与确定性。Q4多核 CPU 下RT 组带宽是单核心限制还是整机总限制解答单 CPU 核心独立限制。每个 CPU 拥有独立的rt_rq与带宽统计配额仅对当前核心生效。若需要整机限制需配合 CPU 亲和性将任务绑定到指定核心。Q5能否将 SCHED_DEADLINE 任务纳入 RT 组调度管控解答默认不支持。RT_GROUP_SCHED仅管控SCHED_FIFO/SCHED_RRDeadline 调度拥有独立的带宽节流体系二者是两套并行的实时资源管控逻辑。六、实践建议与最佳实践6.1 分区与分组规划建议在工控、车载、边缘设备中按照业务安全等级划分 cgroup 组行车控制、设备伺服等高安全业务单独分组并分配充足带宽日志、运维、后台监控等低优先级实时任务合并分组并收紧配额。禁止不同安全等级业务混在同一个 RT 组。6.2 带宽参数调优技巧周期rt_period_us建议统一设为 1000000us1s符合运维观测习惯也匹配内核定时器默认精度带宽配额预留 10%~20% 余量避免业务峰值触发频繁限流导致实时抖动整机所有 RT 组rt_runtime_us总和建议不超过单核心 80%预留 CPU 给中断、内核线程与普通进程。6.3 故障排查流程线上问题标准步骤业务卡顿 → 先执行dmesg查看是否存在bandwidth exhausted限流日志检查进程所属 cgroup核对rt_runtime_us配额是否过小使用ftrace跟踪rt_rq_throttle函数确认限流触发频率排查是否存在异常死循环实时线程必要时结合 CPU 亲和性做核心隔离。6.4 安全与权限规范实时调度与 cgroup 修改需要CAP_SYS_NICE、CAP_SYS_RESOURCE权限线上环境禁止普通用户拥有该权限。生产环境固定 cgroup 目录权限防止恶意进程篡改带宽配额。6.5 内核定制优化若业务对实时抖动要求极高可基于rt_bandwidth结构体二次开发增加限流统计计数器、短时突发带宽补偿机制不要直接删除限流逻辑否则会丢失资源隔离能力。七、总结与应用延伸本文完整讲解了 LinuxRT_GROUP_SCHED实时组调度的设计原理、内核源码、cgroup 配置、压测验证与排障方案。其核心设计思想是以调度组为单位做实时 CPU 带宽配额通过周期定时器 剩余时间扣减的限流机制解决传统 FIFO/RR 实时任务无边界抢占的问题实现多业务实时资源强隔离。从技术层面看RT 组调度是 Linux 混合实时系统的基石将进程管控粒度从 “单进程” 升级为 “业务组”兼顾了实时性与稳定性从工程落地来看该机制是工业控制、车载系统、边缘计算、虚拟化实时分区的标配能力。在实际项目中建议结合CPU 亲和性、进程优先级、RT 组带宽三者组合使用构建分层隔离的实时架构。读者可以基于本文的测试代码修改线程数量、循环负载、带宽参数观测不同压力下系统表现也可以深入阅读rt.c完整源码研究组调度与中断、普通 CFS 任务的抢占关系。掌握 RT 组调度不仅能解决线上实时业务互相干扰的问题也能深入理解 Linux 内核调度框架的分层设计思想可为实时系统论文、内核裁剪、调度策略定制提供扎实的理论与实战支撑。
Linux RT 组调度:RT_GROUP_SCHED 的实时任务资源隔离
简介在传统 Linux 实时调度体系中SCHED_FIFO与SCHED_RR两类软实时任务具备全局高抢占特性。一旦系统内某一组实时业务持续占用 CPU同核心下其他实时进程、普通业务都会被长期阻塞极端场景下甚至引发系统 hung、关键业务超时。在多租户嵌入式设备、工业工控一体机、服务器虚拟化实时分区、车载域控多应用隔离等场景中实时 CPU 资源抢占失控是长期困扰研发与运维的痛点。为解决这一问题Linux 内核引入了RT_GROUP_SCHED组调度机制结合cgroup v1/cgroup v2实现对实时任务的 CPU 带宽配额、资源隔离与流量管控。该机制不再以单个进程为管控单元而是将一组关联实时任务划入同一个调度组通过rt_runtime_us、rt_period_us等参数硬性限制每组实时任务在单个调度周期内可使用的 CPU 时长从内核层面杜绝单个业务组垄断实时计算资源。对于嵌入式 Linux 工程师、实时系统调优人员、虚拟化平台研发、工控系统开发者而言吃透 RT 组调度的内核实现、cgroup 配置、带宽限流逻辑与故障排查方法是搭建高可靠多分区实时系统的必备技能。本文从基础概念、环境搭建、内核源码、实操案例、问题排查到工程最佳实践完整展开内容兼顾源码研读、线上落地、论文与技术报告撰写所有代码与命令均可直接复现全程以一线 Linux 内核工程师实战视角讲解避开纯理论堆砌。一、核心概念与术语解析1.1 传统 Linux 实时调度存在的缺陷Linux 标准实时调度策略分为两种SCHED_FIFO先来先服务实时调度高优先级任务一旦运行会一直占用 CPU 直至主动放弃、阻塞或被更高优先级任务抢占SCHED_RR时间片轮转实时调度同优先级任务按照固定时间片轮流执行仍具备高于普通 CFS 任务的全局抢占权。二者共同短板无带宽限制。只要任务处于就绪态就会持续抢占 CPU。在多业务混合部署场景下一组异常实时任务会直接拖垮整个系统的实时响应能力无法做到业务间资源隔离。1.2 RT_GROUP_SCHED 核心机制概述RT_GROUP_SCHED是内核编译选项开启后启用实时组调度框架核心思想将进程按业务维度划分为不同调度组task group为每个组配置独立的 CPU 实时带宽配额周期时长、最大可用 CPU 时间组内所有SCHED_FIFO/SCHED_RR任务共享本组配额耗尽带宽后本组实时任务被限流让出 CPU组与组之间相互隔离单个组异常不会影响其他实时组。该机制基于 cgroup 实现管控接口用户态通过文件系统读写即可配置带宽无需修改内核代码。1.3 关键参数定义cgroup 实时带宽在 cgroup cpu 子系统下实时调度核心管控参数单位微秒 uscpu.rt_period_us实时带宽的统计周期代表带宽计算的时间窗口全局默认通常为 1000000us1 秒。cpu.rt_runtime_us当前调度组在一个rt_period_us周期内允许所有实时任务累计占用的最大 CPU 时长。该值为 0 表示禁用本组实时任务数值不能超过rt_period_us。计算公式单组实时 CPU 最大占比 rt_runtime_us /rt_period_us × 100%举例周期 1s配额 200000us → 该组实时任务 CPU 上限为 20%。1.4 内核关键数据结构1.4.1 task_group 调度组结构体开启RT_GROUP_SCHED后内核使用struct task_group管理调度组每个 cgroup 对应一个实例// kernel/sched/sched.h struct task_group { /* CFS组调度相关成员本文省略 */ #ifdef CONFIG_RT_GROUP_SCHED /* 每个CPU对应的实时运行队列组 */ struct rt_rq **rt_rq; /* 组级别的实时带宽控制参数 */ int rt_runtime; int rt_period; /* 带宽节流、定时器、统计计数 */ struct rt_bandwidth rt_bw; #endif /* 其他信号、内存、进程链表成员省略 */ };rt_rq每个 CPU 绑定独立的实时运行队列组内实时任务挂载至此rt_runtime/rt_period对应用户态rt_runtime_us/rt_period_usrt_bandwidth实时带宽控制核心结构体包含定时器、剩余时长、限流标记。1.4.2 rt_bandwidth 带宽控制结构体// kernel/sched/rt.c struct rt_bandwidth { /* 周期定时器周期到期后重置实时带宽配额 */ struct hrtimer rt_period_timer; /* 周期定时器触发标识 */ bool timer_active; /* 本组剩余可用实时CPU时间 */ s64 rt_remaining; /* 带宽耗尽标记true表示本组实时任务被限流 */ bool throttled; };当rt_remaining递减至 0throttled置位组内所有实时任务停止调度等待下一个周期重置配额。1.5 调度流转核心流程进程加入指定 cgroup归属对应task_group进程设为SCHED_FIFO/SCHED_RR实时策略进入组内rt_rq就绪队列任务运行时内核递减本组rt_bandwidth-rt_remaining剩余时长为 0 → 触发限流组内实时任务暂停调度周期定时器到期 → 重置rt_remaining清除限流标记恢复调度。二、环境准备2.1 软硬件与版本要求分类版本 / 配置说明操作系统Ubuntu 20.04 / 22.04 64bit主流服务器 / 嵌入式发行版均可内核版本Linux 5.4、5.15、6.1 LTS企业主流长期支持版本逻辑完全兼容硬件架构x86_64推荐 4 核及以上 CPU、4G 内存多组任务压测更明显依赖工具gcc、make、libncurses-dev、bison、flex、cgroup-tools、htop、perf调试工具ftrace、trace-cmd、gdb、strace2.2 内核编译与配置开启 RT_GROUP_SCHED原生系统内核大概率未开启实时组调度需要重新编译内核启用对应开关。步骤 1安装编译依赖sudo apt update sudo apt install build-essential libncurses-dev bison flex libssl-dev libelf-dev cgroup-tools作用安装内核编译工具链、cgroup 操作工具与依赖库。步骤 2下载并解压内核源码# 以 Linux 5.15 LTS 为例 wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.tar.xz tar -xf linux-5.15.tar.xz cd linux-5.15步骤 3内核配置开启关键选项# 继承当前系统内核配置 cp /boot/config-$(uname -r) .config make menuconfig在图形配置界面中依次开启以下选项General setup --- [*] Control Group support # 开启cgroup基础支持 Kernel features --- [*] Group CPU scheduler # 组调度总开关 - Group CPU scheduler [*] Realtime group scheduling # CONFIG_RT_GROUP_SCHED 核心开关 [*] Enable different CONFIG_SCHED_* options --- [*] SCHED_FIFO [*] SCHED_RR # 确保传统实时调度开启 Kernel hacking --- [*] Kernel debugging [*] Function tracer # ftrace 跟踪内核函数用于调试保存配置并退出。步骤 4编译、安装内核并重启# 多核编译加速构建 make -j$(nproc) sudo make modules_install sudo make install # 更新引导项 sudo update-grub重启服务器在 GRUB 菜单选择新编译内核进入。步骤 5验证内核配置# 检查是否开启 RT_GROUP_SCHED zcat /proc/config.gz | grep RT_GROUP_SCHED输出CONFIG_RT_GROUP_SCHEDy即代表配置生效。2.3 cgroup 挂载准备本文使用cgroup v1工业实时系统最常用版本挂载 cpu 子系统# 创建cgroup根目录 sudo mkdir /sys/fs/cgroup/cpu sudo mount -t tmpfs cgroup_root /sys/fs/cgroup/cpu # 挂载cpu子系统包含实时带宽控制 sudo mount -t cgroup -o cpu none /sys/fs/cgroup/cpu作用cgroup 文件系统挂载完成后即可通过目录文件配置实时带宽。三、应用场景RT 组调度是多业务实时系统的核心隔离手段广泛落地于工业与嵌入式领域。工业工控一体机常同时运行设备控制、人机交互、日志采集三类进程将三类业务划分为独立 cgroup 组分别配置不同实时 CPU 带宽可防止高负载控制任务抢占交互界面资源保证操作响应流畅。车载域控制器中整车动力控制、多媒体娱乐、车载诊断程序分属不同实时组借助 rt_runtime_us 限制各组 CPU 上限避免娱乐进程影响行车安全类高优先级实时任务。在云边缘实时服务器场景下多租户实时音视频解码、数据采集服务通过 RT 组调度做资源切片单租户异常不会扩散至其他租户大幅提升集群整体稳定性与服务可用性。四、实际案例与步骤代码 实操本章节分为内核源码解析、用户态测试程序、cgroup 带宽配置、功能验证四部分所有代码可直接复制运行。4.1 内核源码实时带宽限流核心逻辑4.1.1 实时任务带宽扣减逻辑内核在实时任务运行时周期性扣除本组剩余 CPU 时间代码位于kernel/sched/rt.c/* * 实时任务运行时扣除对应调度组的带宽 * rq: 当前CPU运行队列 * rt_rq: 当前组的实时运行队列 * delta: 本次运行消耗的CPU时间纳秒 */ static void sched_rt_account_runtime(struct rq *rq, struct rt_rq *rt_rq, u64 delta) { struct task_group *tg rt_rq-tg; struct rt_bandwidth *rt_bw tg-rt_bw; /* 未限流则扣除剩余时间 */ if (!rt_bw-throttled) { rt_bw-rt_remaining - delta; /* 剩余时间小于等于0触发限流 */ if (rt_bw-rt_remaining 0) { rt_bw-throttled true; /* 暂停本组所有实时任务调度 */ rt_rq_throttle(rt_rq); printk(KERN_WARNING RT group bandwidth exhausted, group throttled\n); } } }代码说明每次任务运行产生时间片消耗调用该函数扣减rt_remaining带宽耗尽时置位throttled标记调用rt_rq_throttle暂停组内实时队列内核打印警告日志可通过dmesg观测限流事件。4.1.2 周期定时器重置带宽周期定时器是带宽恢复的核心每个周期结束后重置可用 CPU 时间/* 实时带宽周期定时器回调函数 */ static enum hrtimer_restart rt_period_timer(struct hrtimer *timer) { struct rt_bandwidth *rt_bw container_of(timer, struct rt_bandwidth, rt_period_timer); struct task_group *tg container_of(rt_bw, struct task_group, rt_bw); int runtime tg-rt_runtime; /* 重置剩余可用实时时间 */ rt_bw-rt_remaining runtime * NSEC_PER_USEC; /* 清除限流标记 */ rt_bw-throttled false; /* 唤醒被限流的实时队列恢复调度 */ rt_unthrottle_group(tg); /* 重新启动高精度定时器 */ hrtimer_forward_now(timer, ns_to_ktime(tg-rt_period * NSEC_PER_USEC)); return HRTIMER_RESTART; }代码说明定时器按照rt_period_us周期触发统一恢复全组带宽解除限流。4.2 编写实时压测测试程序编写一个死循环SCHED_FIFO实时任务用于占用 CPU、触发带宽限流。文件命名rt_stress.c。#include stdio.h #include stdlib.h #include unistd.h #include pthread.h #include linux/sched.h #include sys/syscall.h #define RT_PRIORITY 80 // 实时优先级范围 1~99数值越大优先级越高 /* 设置当前线程为 SCHED_FIFO 实时调度 */ int set_sched_fifo(void) { struct sched_param param; param.sched_priority RT_PRIORITY; // 设置当前线程调度策略与优先级 if (pthread_setschedparam(pthread_self(), SCHED_FIFO, param) 0) { perror(pthread_setschedparam failed); return -1; } return 0; } /* 实时负载线程死循环占用CPU */ void *rt_worker(void *arg) { set_sched_fifo(); printf(RT worker thread started, PID: %d\n, gettid()); // 纯计算负载持续占用CPU while (1) { unsigned long i; for (i 0; i 10000000; i); } return NULL; } int main(int argc, char *argv[]) { pthread_t tid; printf(Create RT stress task\n); // 创建实时负载线程 if (pthread_create(tid, NULL, rt_worker, NULL) 0) { perror(pthread_create failed); return -1; } pthread_join(tid, NULL); return 0; }代码作用创建高优先级 FIFO 实时线程无限循环占用 CPU用于模拟异常实时任务。编译命令gcc rt_stress.c -o rt_stress -lpthread4.3 创建 cgroup 分组并配置实时带宽我们创建两个独立 cgroup 组rt_group1、rt_group2做隔离对比测试。步骤 1创建 cgroup 目录cd /sys/fs/cgroup/cpu sudo mkdir rt_group1 rt_group2每个目录自动生成cpu.rt_period_us、cpu.rt_runtime_us等控制文件。步骤 2统一设置调度周期全局窗口 1 秒# 周期1000000 us 1s echo 1000000 | sudo tee rt_group1/cpu.rt_period_us echo 1000000 | sudo tee rt_group2/cpu.rt_period_us步骤 3配置差异化带宽配额# rt_group1配额 200000us → 最大20% CPU echo 200000 | sudo tee rt_group1/cpu.rt_runtime_us # rt_group2配额 500000us → 最大50% CPU echo 500000 | sudo tee rt_group2/cpu.rt_runtime_us步骤 4将测试进程加入 cgroup 组新开终端后台运行压测程序sudo ./rt_stress # 获取进程PID PID$! echo RT stress PID: $PID将 PID 加入rt_group1echo $PID | sudo tee /sys/fs/cgroup/cpu/rt_group1/cgroup.procs4.4 功能验证与观测4.4.1 查看 CPU 占用与限流状态使用htop观测 CPU 使用率htop现象进程 CPU 占用稳定在20% 左右不会占满核心证明带宽限制生效。4.4.2 查看内核限流日志dmesg -w持续观察当组内实时带宽耗尽时会打印内核警告RT group bandwidth exhausted, group throttled代表 RT 组调度已触发限流。4.4.3 跨组隔离验证再启动一个压测进程加入rt_group2sudo ./rt_stress PID2$! echo $PID2 | sudo tee /sys/fs/cgroup/cpu/rt_group2/cgroup.procs观测结果两个进程分别按照 20%、50% 配额占用 CPU互不干扰资源隔离生效。4.5 使用 ftrace 跟踪 RT 组调度内核函数跟踪带宽扣减、限流、定时器函数深入观测内核行为# 开启ftrace echo function /sys/kernel/debug/tracing/current_tracer # 设置跟踪函数 echo sched_rt_account_runtime /sys/kernel/debug/tracing/set_ftrace_filter echo rt_period_timer /sys/kernel/debug/tracing/set_ftrace_filter echo rt_rq_throttle /sys/kernel/debug/tracing/set_ftrace_filter # 开启跟踪 echo 1 /sys/kernel/debug/tracing/tracing_on # 查看跟踪日志 cat /sys/kernel/debug/tracing/trace作用可清晰看到带宽扣减、限流触发、周期重置的完整调用链路。五、常见问题与解答Q1配置完 cpu.rt_runtime_us 后实时任务依然占满 CPU限制不生效解答优先排查三点1. 内核未开启CONFIG_RT_GROUP_SCHED使用zcat /proc/config.gz验证2. 进程未正确写入对应 cgroup 的cgroup.procs3. 只配置了子组未关闭根 cgroup 的实时带宽根组默认无限制。Q2修改 cpu.rt_period_us 时报错 “Operation not permitted”解答rt_period_us属于组全局周期仅根 cgroup 可修改子 cgroup 只能修改rt_runtime_us。统一在/sys/fs/cgroup/cpu根目录配置周期即可。Q3实时任务被限流后为什么不是立即恢复而是等待固定周期解答RT 组调度采用基于周期的带宽限流算法而非令牌桶。必须等待rt_period_us定时器到期内核才会统一重置剩余 CPU 时间以此保证带宽统计的公平性与确定性。Q4多核 CPU 下RT 组带宽是单核心限制还是整机总限制解答单 CPU 核心独立限制。每个 CPU 拥有独立的rt_rq与带宽统计配额仅对当前核心生效。若需要整机限制需配合 CPU 亲和性将任务绑定到指定核心。Q5能否将 SCHED_DEADLINE 任务纳入 RT 组调度管控解答默认不支持。RT_GROUP_SCHED仅管控SCHED_FIFO/SCHED_RRDeadline 调度拥有独立的带宽节流体系二者是两套并行的实时资源管控逻辑。六、实践建议与最佳实践6.1 分区与分组规划建议在工控、车载、边缘设备中按照业务安全等级划分 cgroup 组行车控制、设备伺服等高安全业务单独分组并分配充足带宽日志、运维、后台监控等低优先级实时任务合并分组并收紧配额。禁止不同安全等级业务混在同一个 RT 组。6.2 带宽参数调优技巧周期rt_period_us建议统一设为 1000000us1s符合运维观测习惯也匹配内核定时器默认精度带宽配额预留 10%~20% 余量避免业务峰值触发频繁限流导致实时抖动整机所有 RT 组rt_runtime_us总和建议不超过单核心 80%预留 CPU 给中断、内核线程与普通进程。6.3 故障排查流程线上问题标准步骤业务卡顿 → 先执行dmesg查看是否存在bandwidth exhausted限流日志检查进程所属 cgroup核对rt_runtime_us配额是否过小使用ftrace跟踪rt_rq_throttle函数确认限流触发频率排查是否存在异常死循环实时线程必要时结合 CPU 亲和性做核心隔离。6.4 安全与权限规范实时调度与 cgroup 修改需要CAP_SYS_NICE、CAP_SYS_RESOURCE权限线上环境禁止普通用户拥有该权限。生产环境固定 cgroup 目录权限防止恶意进程篡改带宽配额。6.5 内核定制优化若业务对实时抖动要求极高可基于rt_bandwidth结构体二次开发增加限流统计计数器、短时突发带宽补偿机制不要直接删除限流逻辑否则会丢失资源隔离能力。七、总结与应用延伸本文完整讲解了 LinuxRT_GROUP_SCHED实时组调度的设计原理、内核源码、cgroup 配置、压测验证与排障方案。其核心设计思想是以调度组为单位做实时 CPU 带宽配额通过周期定时器 剩余时间扣减的限流机制解决传统 FIFO/RR 实时任务无边界抢占的问题实现多业务实时资源强隔离。从技术层面看RT 组调度是 Linux 混合实时系统的基石将进程管控粒度从 “单进程” 升级为 “业务组”兼顾了实时性与稳定性从工程落地来看该机制是工业控制、车载系统、边缘计算、虚拟化实时分区的标配能力。在实际项目中建议结合CPU 亲和性、进程优先级、RT 组带宽三者组合使用构建分层隔离的实时架构。读者可以基于本文的测试代码修改线程数量、循环负载、带宽参数观测不同压力下系统表现也可以深入阅读rt.c完整源码研究组调度与中断、普通 CFS 任务的抢占关系。掌握 RT 组调度不仅能解决线上实时业务互相干扰的问题也能深入理解 Linux 内核调度框架的分层设计思想可为实时系统论文、内核裁剪、调度策略定制提供扎实的理论与实战支撑。