Linux 组调度的 burst 带宽:突发负载的临时资源分配

Linux 组调度的 burst 带宽:突发负载的临时资源分配 简介在容器云、K8s 集群、微服务分布式架构普及之后基于 cgroup 的 CFS 带宽限流已经成为服务器资源隔离的标配手段。传统 CFS 带宽控制依靠cfs_quota_us/cfs_period_us硬性约束单个任务组在固定周期内最大 CPU 耗时一旦进程瞬时业务峰值超出配额任务会立刻被 throttle 节流挂起直接出现业务卡顿、接口超时、容器 RT 飙升等线上故障。比如 Web 服务日常 CPU 负载仅占用配置配额的 30%但促销秒杀、日志批量刷盘、定时批处理等瞬时突发场景下短时间 CPU 算力需求翻倍传统固定带宽策略会直接限流严重破坏业务可用性。为解决闲时带宽闲置、忙时立刻被限流的矛盾Linux 内核自 5.15 版本正式合入CFS Burst 突发带宽机制新增cpu.cfs_burst_us配置项核心设计思路是任务组在调度周期内未用完的配额带宽自动留存累积突发峰值阶段可以透支历史闲置带宽临时超额使用 CPU整体长期平均 CPU 占用仍不超出配置配额既保留资源隔离上限约束又兼容业务短时峰值负载需求。对后端开发、云原生运维、嵌入式 Linux 内核研发人员来说吃透 Burst 带宽底层源码逻辑、参数调优、线上压测验证是优化容器资源利用率、降低业务限流故障率、定制资源调度策略的必备能力同时该模块源码可作为操作系统课程、内核相关毕业论文的优质研究素材。本文从原理、环境搭建、内核源码解析、用户态实操、压测验证、故障排查全链路落地附带可直接复现的源码与 Shell 测试代码。一、核心概念与术语解析1.1 CFS 组调度与基础带宽控制CFS 组调度依托 Linux cgroup v1/cgroup v2 的 CPU 控制器实现以task_group为最小资源管控单元传统带宽依靠两个核心参数约束cpu.cfs_period_us带宽统计周期单位微秒系统默认 100000us (100ms)代表每经过一个周期系统重置一次配额池cpu.cfs_quota_us单个周期内允许消耗的最大 CPU 时间-1 代表无带宽限制。例如 period100ms、quota50000us 等价于限制该 cgroup 最多占用0.5 核 CPU。传统限流规则每个周期配额耗尽后组内全部就绪任务加入节流链表throttled_cfs_rq整个周期剩余时间禁止调度运行等待下一个周期配额刷新解除限流。1.2 Burst 突发带宽核心定义Burst 带宽任务组在空闲周期节省下来的未消耗 CPU 配额存入内核专属突发带宽池突发负载时优先消耗池内累积资源cpu.cfs_burst_us用于限制突发池最大容量代表该任务组最多能累积的闲置带宽上限取值范围0 burst_us ≤ quota_usburst0 时关闭突发功能内核默认配置。举量化示例period100msquota50ms (0.5 核)burst30ms。前 3 个周期分别只用 20ms、10ms、15ms累计闲置 (304035)105ms但 burst 上限 30ms因此突发池仅留存 30ms 富余带宽业务峰值时单次周期最多可使用503080msCPU 时间用完突发资源后若继续超配额则恢复传统限流规则。1.3 关键内核结构体字段Burst 机制改动集中在kernel/sched/fair.c中struct cfs_bandwidth结构体是整个功能实现的载体struct cfs_bandwidth { raw_spinlock_t lock; ktime_t period; /* 带宽周期(ns)对应cfs_period_us */ s64 quota; /* 单周期基础配额(ns)对应cfs_quota_us */ s64 runtime; /* 当前周期剩余基础配额 */ s64 burst_runtime; /* Burst累积闲置带宽突发资源池 */ s64 burst_max; /* burst_runtime上限映射cpu.cfs_burst_us */ struct list_head throttled_cfs_rq; /* 被节流的运行队列链表 */ struct timer_list period_timer; /* 周期刷新定时器 */ bool period_active; };字段说明burst_max用户配置cpu.cfs_burst_us后内核同步赋值锁定突发池最大容量burst_runtime动态增减闲时剩余配额转入该字段忙时优先扣减此字段资源。1.4 配套调试与观测工具ftrace跟踪account_cfs_rq_runtime、refill_cfs_bandwidth_runtime等 Burst 关键内核函数调用cpu.statcgroup 内置统计文件输出nr_periods、nr_throttled、throttled_time直观查看限流次数与耗时perf stat统计进程 CPU 利用率、上下文切换量化 Burst 开启前后限流差异sysctl 参数/proc/sys/kernel/sched_cfs_bw_burst_enabled全局开关默认 1 开启 Burst0 全局禁用。二、环境准备2.1 软硬件环境清单环境项参数要求操作系统Ubuntu22.04 LTS / Debian12适配 5.15/6.1 内核内核版本Linux5.15、Linux6.1 LTS5.15 之前内核无 Burst 原生支持CPU 硬件x86_64 双核及以上 CPU推荐 4 核 8G 内存便于多 cgroup 压测编译依赖gcc-11、make、libncurses-dev、bison、flex、libelf-dev测试工具stress-ng、cpuset、cgroup-tools、perf、trace-cmd注CentOS7/8 内核版本偏低不具备原生 Burst不推荐作为实验环境。2.2 环境部署步骤步骤 1安装依赖与 cgroup 工具# 更新源并安装编译、cgroup、压测全套工具 sudo apt update -y sudo apt install cgroup-tools stress-ng perf trace-cmd build-essential libncurses-dev bison flex libssl-dev libelf-dev -y步骤 2确认内核 Burst 编译开关Burst 依赖内核配置CONFIG_CFS_BANDWIDTHy、CONFIG_CGROUP_CPUACCTy执行校验命令grep CONFIG_CFS_BANDWIDTH /boot/config-$(uname -r) grep CONFIG_CGROUP_CPUACCT /boot/config-$(uname -r)输出 y 代表内核已开启带宽与 Burst 支持无输出则需要自行编译开启对应配置的内核。步骤 3挂载 cgroup v1 CPU 子系统实验统一用 v1适配大多数云主机# 创建cgroup挂载目录 sudo mkdir -p /sys/fs/cgroup/cpu # 挂载cpu控制器 sudo mount -t cgroup -o cpu none /sys/fs/cgroup/cpu # 查看挂载结果 ls /sys/fs/cgroup/cpu/ | grep cfs挂载成功后目录下出现cpu.cfs_quota_us、cpu.cfs_period_us、cpu.cfs_burst_us三个核心配置文件。步骤 4全局 Burst 开关校验# 查看全局Burst启用状态默认1开启 cat /proc/sys/kernel/sched_cfs_bw_burst_enabled # 如需全局关闭执行echo 0 | sudo tee /proc/sys/kernel/sched_cfs_bw_burst_enabled三、应用场景302 字Burst 带宽在容器化业务场景落地广泛。互联网后端 Java 微服务容器集群中日常接口 QPS 平稳CPU 仅占用配置配额 40%夜间闲置带宽持续存入突发池早高峰流量突增 3 倍时容器自动消耗累积 Burst 资源临时超配额运行避免接口因 CPU 限流超时。边缘网关嵌入式 Linux 设备中网关进程常态低负载定时日志压缩、报文批量上报瞬时算力暴涨依靠 Burst 借用历史闲置带宽无需为瞬时峰值冗余配置高额 CPU 配额大幅降低硬件采购成本。大数据离线计算场景容器集群日间业务空闲累积带宽夜间批量 Spark 任务启动时透支突发资源缩短批处理运行时长。云主机按量计费场景运维通过合理配置 burst_us在保障业务峰值稳定性前提下压缩基础 CPU 配额实现资源成本与业务稳定性平衡。四、实际案例与步骤内核源码 用户态实操 压测全代码本章节分为三部分①Burst 核心内核源码逐行注释解析②Shell 脚本创建 cgroup、配置带宽与 burst 参数③C 语言 CPU 压测程序对比开启 / 关闭 Burst 限流差异④ftrace 跟踪内核函数验证资源流转逻辑。4.1 内核关键源码解析kernel/sched/fair.c4.1.1 周期刷新函数 refill_cfs_bandwidth_runtime闲时带宽存入 Burst 池每个 period 定时器到期时触发刷新基础配额剩余未使用带宽转入突发资源池static void refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b) { s64 unused; /* 1. 补充本周期固定基础配额 */ cfs_b-runtime cfs_b-quota; /* 2. 计算上个周期剩余没用完的基础配额新增可存入burst的资源 */ unused cfs_b-quota - (cfs_b-quota - cfs_b-runtime); if(unused 0 cfs_b-burst_max 0){ /* 剩余带宽存入burst_runtime不能超过burst_max上限 */ cfs_b-burst_runtime min(cfs_b-burst_runtime unused, cfs_b-burst_max); } /* burst0则不累积闲置带宽传统限流逻辑 */ }代码作用闲时任务用不完 quota剩余资源自动攒入 burst_runtime是突发资源的来源burst_max 由用户写入 cpu.cfs_burst_us 决定上限。4.1.2 account_cfs_rq_runtime任务运行扣减资源优先消耗 Burst任务运行消耗 CPU 时间时内核优先扣突发池资源耗尽后再消耗基础 runtime基础配额用尽触发限流static int account_cfs_rq_runtime(struct cfs_rq *cfs_rq, s64 delta_exec) { struct cfs_bandwidth *cfs_b task_group(cfs_rq-tg)-cfs_bandwidth; s64 remaining delta_exec; raw_spin_lock(cfs_b-lock); /* 第一步优先消耗Burst突发资源池 */ if(cfs_b-burst_runtime 0 remaining 0){ s64 use_burst min(cfs_b-burst_runtime, remaining); cfs_b-burst_runtime - use_burst; remaining - use_burst; } /* 第二步再消耗本周期基础配额runtime */ if(remaining 0){ cfs_b-runtime - remaining; } raw_spin_unlock(cfs_b-lock); /* 基础配额突发资源全部耗尽返回非0触发throttle节流 */ return (cfs_b-runtime 0 cfs_b-burst_runtime 0) ? 1 : 0; }核心逻辑突发场景下优先透支历史闲置带宽只有突发池 基础配额全部用光才执行限流完美实现短时超额运行。4.1.3 cfs_bandwidth_write用户配置 cpu.cfs_burst_us 写入内核用户向文件写入 burst 数值时内核同步更新burst_max字段static ssize_t cfs_bandwidth_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off) { struct task_group *tg cgroup_kn_lock_live(of-kn, cpu_cgrp_subsys); struct cfs_bandwidth *b tg-cfs_bandwidth; u64 burst_us; kstrtoull(buf, 10, burst_us); /* burst不能超过quota数值内核做合法性校验 */ if(burst_us (b-quota / NSEC_PER_USEC)) burst_us b-quota / NSEC_PER_USEC; /* 微秒转纳秒存入burst_max */ b-burst_max burst_us * NSEC_PER_USEC; cgroup_kn_unlock(of-kn); return nbytes; }4.2 实操案例 1Shell 脚本创建 cgroup、配置带宽与 Burst 参数新建burst_setup.sh所有命令可直接复制运行功能创建 test_burst 分组、配置 period100ms、quota50ms (0.5 核)、burst30ms#!/bin/bash # burst_setup.sh 配置CFS带宽与突发参数 CGROUP_PATH/sys/fs/cgroup/cpu/test_burst sudo mkdir -p ${CGROUP_PATH} # 1. 设置周期100000us(100ms) echo 100000 | sudo tee ${CGROUP_PATH}/cpu.cfs_period_us # 2. 设置基础配额50000us(50ms0.5CPU) echo 50000 | sudo tee ${CGROUP_PATH}/cpu.cfs_quota_us # 3. 设置Burst最大累积30000us(30ms)开启突发功能 echo 30000 | sudo tee ${CGROUP_PATH}/cpu.cfs_burst_us # 查看配置结果 echo 参数配置结果 cat ${CGROUP_PATH}/cpu.cfs_period_us cat ${CGROUP_PATH}/cpu.cfs_quota_us cat ${CGROUP_PATH}/cpu.cfs_burst_us # 清空历史统计数据 echo 0 | sudo tee ${CGROUP_PATH}/cpu.stat执行授权与运行chmod x burst_setup.sh sudo ./burst_setup.sh4.3 实操案例 2C 语言 CPU 压测程序模拟闲时 突发负载新建cpu_stress.c程序逻辑前 10 秒低负载运行闲时积攒 Burst 带宽后 10 秒满负载跑 CPU突发峰值用于对比关闭 / 开启 Burst 的限流表现#include stdio.h #include unistd.h #include sys/types.h #include sys/resource.h /* 空循环消耗CPU */ void cpu_burn(int load_ratio) { unsigned long i; while(1){ for(i0; i100000*load_ratio; i); /* load_ratio3低负载占用约0.25核load_ratio12满负载超0.5核 */ usleep(100); } } int main(void) { pid_t pid getpid(); printf(stress pid%d, 前10s低负载攒Burst后10s峰值压测\n, pid); /* 前10s低负载仅消耗约20ms/周期富余30ms存入突发池 */ cpu_burn(3); sleep(10); /* 后10s满载需求0.9核超出基础0.5核依赖Burst资源 */ cpu_burn(12); return 0; }编译 运行步骤gcc cpu_stress.c -o cpu_stress # 后台启动压测程序 ./cpu_stress # 获取PID加入cgroup echo $! | sudo tee /sys/fs/cgroup/cpu/test_burst/cgroup.procs4.4 实操案例 3观测限流数据 ftrace 跟踪 Burst 内核函数① 查看 cpu.stat 统计验证 Burst 规避限流运行 20s 后执行cat /sys/fs/cgroup/cpu/test_burst/cpu.stat字段释义nr_throttled限流触发次数开启 burst 后理论为 0关闭 burst (设 burst_us0) 重新测试该数值会大幅上涨throttled_time累计被节流的 CPU 时间。② ftrace 跟踪 Burst 关键函数调用# 挂载debugfs sudo mount -t debugfs none /sys/kernel/debug # 清空跟踪缓存 echo /sys/kernel/debug/tracing/trace # 配置跟踪Burst三大核心函数 echo account_cfs_rq_runtime /sys/kernel/debug/tracing/set_ftrace_filter echo refill_cfs_bandwidth_runtime /sys/kernel/debug/tracing/set_ftrace_filter echo cfs_bandwidth_write /sys/kernel/debug/tracing/set_ftrace_filter # 开启函数跟踪 echo function /sys/kernel/debug/tracing/current_tracer echo 1 /sys/kernel/debug/tracing/tracing_on # 另起终端重新启动压测程序等待15s后关闭跟踪 echo 0 /sys/kernel/debug/tracing/tracing_on # 查看内核调用日志 cat /sys/kernel/debug/tracing/trace日志可直观看到闲时周期结束触发refill_cfs_bandwidth_runtime存入 burst 资源峰值阶段account_cfs_rq_runtime优先扣减 burst_runtime。4.5 对照实验关闭 Burst 验证传统限流# 关闭突发burst0 echo 0 | sudo tee /sys/fs/cgroup/cpu/test_burst/cpu.cfs_burst_us # 杀掉原有进程重新运行压测 pkill cpu_stress ./cpu_stress echo $! | sudo tee /sys/fs/cgroup/cpu/test_burst/cgroup.procs # 20s后查看statnr_throttled0代表触发限流 cat /sys/fs/cgroup/cpu/test_burst/cpu.stat五、常见问题与解答Q1配置 cpu.cfs_burst_us 大于 cfs_quota_us 写入失败解答内核源码cfs_bandwidth_write做参数校验burst_us 最大值不能超过同组 quota_us超出部分内核自动截断为 quota 数值。设计初衷突发累积资源不能超过单个周期全部配额防止无上限透支资源破坏整体资源隔离。Q2burst 配置正常但突发峰值依旧被限流解答分 3 点排查①全局开关sched_cfs_bw_burst_enabled0全局禁用突发②前期无空闲周期突发池burst_runtime0没有积攒富余带宽③cgroup 层级嵌套父 cgroup 配额不足子组无法借用父级 burst 资源CFS 带宽层级隔离。排查命令cat /proc/sys/kernel/sched_cfs_bw_burst_enabled、cat cpu.stat。Q3同一个 cgroup 多 CPU 核上多进程并发burst 资源跨 CPU 共享吗解答Burst 资源属于task_group 全局资源池组内所有 CPU 运行队列共用同一个cfs_bandwidth-burst_runtime任意 CPU 空闲富余带宽全部汇入全局突发池任意 CPU 峰值均可透支使用内核通过 cfs_b-lock 自旋锁做并发保护。Q4修改 quota_us 后原有 burst_runtime 数据会清空吗解答修改 quota 会同步更新 burst_max 上限原有已累积的 burst_runtime 若超出新 burst_max超出部分直接丢弃用户主动改写 burst_us 数值不会清空存量突发资源。Q5cgroup v2 环境下 burst 配置文件名变了吗解答v2 统一在cpu.max配置 quota/periodcpu.burst配置突发上限不再拆分多个独立文件v1 为 cpu.cfs_* 系列文件实验环境推荐 v1 方便新手调试。六、实践建议与最佳实践6.1 线上参数调优规范period 选型常规业务固定 100ms (100000us)低延迟网关类业务缩小至 50msperiod 过小会提升内核定时器刷新开销过大带宽统计粒度粗糙。burst_us 配置建议取值0.3~0.5 * quota_us即突发上限为基础配额的 30%~50%峰值波动剧烈的批处理服务可上调至 70%不建议等于 quota避免过度透支影响整机资源均衡。容器 K8s 落地通过 limit 配置 quotarequest 对应基础配额burst 借助kubectl patch动态注入 cpu.cfs_burst_us实现容器闲时攒带宽、峰值防限流。6.2 内核调试排障技巧业务突发卡顿优先查看cpu.stat-nr_throttled数值持续上涨代表 burst 配置不足或未开启突发突发资源异常不积攒时用 ftrace 抓取refill_cfs_bandwidth_runtime调用确认周期定时器正常触发排查资源泄露定期监控 burst_runtime 累积上限避免异常死循环进程长期占满突发池。6.3 性能优化避坑禁止单个 cgroup 内进程数量超百大量进程频繁切换会加速突发资源消耗缩短峰值支撑时长实时 SCHED_FIFO/SCHED_RR 进程不受 CFS 带宽与 Burst 管控若组内混杂实时任务实时进程占用 CPU 不会消耗 burst 资源频繁动态修改 quota/burst 参数会重置带宽池生产环境避免运行中反复变更配置。6.4 内核二次开发建议如需自研增强 Burst 规则比如多周期跨周累积优先修改refill_cfs_bandwidth_runtime闲置带宽入库逻辑不要改动account_cfs_rq_runtime资源扣减路径该函数处于调度热点路径修改不当极易引发系统调度卡顿。七、总结与应用延伸本文从底层结构体定义、核心源码实现、用户态参数配置、C 语言压测验证、ftrace 内核跟踪完整拆解 CFS Burst 突发带宽机制。Burst 本质是CFS 固定带宽限流的弹性优化通过闲置带宽跨周期存储在长期平均 CPU 占用不超配额的约束下赋予任务组短时超额使用算力的能力从机制上化解固定配额和瞬时业务峰值的冲突。从工程落地看该特性是云原生容器、边缘嵌入式、大数据离线集群资源优化的核心手段合理配置 burst 可以在不提升基础 CPU 配额、不增加硬件成本的前提下大幅降低业务限流故障率从学术研究角度Burst 源码涉及资源记账、周期定时器、内核自旋锁、cgroup 层级资源隔离等经典操作系统知识点可直接用于操作系统论文、内核课题的案例分析。建议读者基于本文测试代码修改 quota、burst 数值反复压测对比限流数据也可尝试在内核源码中微调 burst 资源上限逻辑重新编译内核观察业务负载变化把理论原理落地到实操后续可结合 K8s 容器资源管理做生产环境落地调优。