当前位置: 首页 > news >正文

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为最小资源管控单元,传统带宽依靠两个核心参数约束:

  1. cpu.cfs_period_us:带宽统计周期,单位微秒,系统默认 100000us (100ms),代表每经过一个周期系统重置一次配额池;
  2. cpu.cfs_quota_us:单个周期内允许消耗的最大 CPU 时间,-1 代表无带宽限制。例如 period=100ms、quota=50000us 等价于限制该 cgroup 最多占用0.5 核 CPU

传统限流规则:每个周期配额耗尽后,组内全部就绪任务加入节流链表throttled_cfs_rq,整个周期剩余时间禁止调度运行,等待下一个周期配额刷新解除限流。

1.2 Burst 突发带宽核心定义

Burst 带宽:任务组在空闲周期节省下来的未消耗 CPU 配额,存入内核专属突发带宽池,突发负载时优先消耗池内累积资源;cpu.cfs_burst_us用于限制突发池最大容量,代表该任务组最多能累积的闲置带宽上限,取值范围0 < burst_us ≤ quota_us,burst=0 时关闭突发功能(内核默认配置)。

举量化示例:

period=100ms,quota=50ms (0.5 核),burst=30ms。前 3 个周期分别只用 20ms、10ms、15ms,累计闲置 (30+40+35)=105ms,但 burst 上限 30ms,因此突发池仅留存 30ms 富余带宽;业务峰值时单次周期最多可使用50+30=80msCPU 时间,用完突发资源后若继续超配额则恢复传统限流规则。

1.3 关键内核结构体字段

Burst 机制改动集中在kernel/sched/fair.cstruct 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 配套调试与观测工具

  1. ftrace:跟踪account_cfs_rq_runtimerefill_cfs_bandwidth_runtime等 Burst 关键内核函数调用;
  2. cpu.stat:cgroup 内置统计文件,输出nr_periods、nr_throttled、throttled_time,直观查看限流次数与耗时;
  3. perf stat:统计进程 CPU 利用率、上下文切换,量化 Burst 开启前后限流差异;
  4. sysctl 参数/proc/sys/kernel/sched_cfs_bw_burst_enabled全局开关,默认 1 开启 Burst,0 全局禁用。

二、环境准备

2.1 软硬件环境清单

环境项参数要求
操作系统Ubuntu22.04 LTS / Debian12(适配 5.15/6.1 内核)
内核版本Linux5.15+、Linux6.1 LTS(5.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_BANDWIDTH=yCONFIG_CGROUP_CPUACCT=y,执行校验命令:

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.c)

4.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); } /* burst=0则不累积闲置带宽,传统限流逻辑 */ }

代码作用:闲时任务用不完 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 实操案例 1:Shell 脚本创建 cgroup、配置带宽与 Burst 参数

新建burst_setup.sh,所有命令可直接复制运行,功能:创建 test_burst 分组、配置 period=100ms、quota=50ms (0.5 核)、burst=30ms:

#!/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(50ms=0.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.sh

4.3 实操案例 2:C 语言 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(i=0; i<100000*load_ratio; i++); /* load_ratio=3:低负载,占用约0.25核;load_ratio=12:满负载超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.procs

4.4 实操案例 3:观测限流数据 + ftrace 跟踪 Burst 内核函数

① 查看 cpu.stat 统计,验证 Burst 规避限流

运行 20s 后执行:

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

字段释义:

  • nr_throttled:限流触发次数,开启 burst 后理论为 0;关闭 burst (设 burst_us=0) 重新测试,该数值会大幅上涨;
  • 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 验证传统限流

# 关闭突发,burst=0 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后查看stat,nr_throttled>0代表触发限流 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 数值。设计初衷:突发累积资源不能超过单个周期全部配额,防止无上限透支资源破坏整体资源隔离。

Q2:burst 配置正常,但突发峰值依旧被限流?

解答:分 3 点排查:①全局开关sched_cfs_bw_burst_enabled=0,全局禁用突发;②前期无空闲周期,突发池burst_runtime=0没有积攒富余带宽;③cgroup 层级嵌套,父 cgroup 配额不足,子组无法借用父级 burst 资源,CFS 带宽层级隔离。排查命令cat /proc/sys/kernel/sched_cfs_bw_burst_enabledcat 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 数值不会清空存量突发资源。

Q5:cgroup v2 环境下 burst 配置文件名变了吗?

解答:v2 统一在cpu.max配置 quota/period,cpu.burst配置突发上限,不再拆分多个独立文件,v1 为 cpu.cfs_* 系列文件,实验环境推荐 v1 方便新手调试。

六、实践建议与最佳实践

6.1 线上参数调优规范

  1. period 选型:常规业务固定 100ms (100000us),低延迟网关类业务缩小至 50ms;period 过小会提升内核定时器刷新开销,过大带宽统计粒度粗糙。
  2. burst_us 配置:建议取值0.3~0.5 * quota_us,即突发上限为基础配额的 30%~50%;峰值波动剧烈的批处理服务可上调至 70%,不建议等于 quota,避免过度透支影响整机资源均衡。
  3. 容器 K8s 落地:通过 limit 配置 quota,request 对应基础配额,burst 借助kubectl patch动态注入 cpu.cfs_burst_us,实现容器闲时攒带宽、峰值防限流。

6.2 内核调试排障技巧

  1. 业务突发卡顿优先查看cpu.stat->nr_throttled,数值持续上涨代表 burst 配置不足或未开启突发;
  2. 突发资源异常不积攒时,用 ftrace 抓取refill_cfs_bandwidth_runtime调用,确认周期定时器正常触发;
  3. 排查资源泄露:定期监控 burst_runtime 累积上限,避免异常死循环进程长期占满突发池。

6.3 性能优化避坑

  1. 禁止单个 cgroup 内进程数量超百,大量进程频繁切换会加速突发资源消耗,缩短峰值支撑时长;
  2. 实时 SCHED_FIFO/SCHED_RR 进程不受 CFS 带宽与 Burst 管控,若组内混杂实时任务,实时进程占用 CPU 不会消耗 burst 资源;
  3. 频繁动态修改 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 容器资源管理做生产环境落地调优。

http://www.jsqmd.com/news/943938/

相关文章:

  • 2026分子蒸馏生产厂家精选指南:从真空精度筛选靠谱供货商 - 品牌推荐大师
  • 理论框架总搭不起来?师兄推荐这几个AI写作辅助平台
  • 自行车轮POV显示:基于Arduino与WS2812B的视觉暂留动画实现
  • 如何快速掌握EmotiVoice:2000+音色情感语音合成的终极实战指南
  • 英伟达黄仁勋与Marvell CEO同台,揭示AI基础设施下一个决定性战场——连接!
  • ShawzinBot终极指南:MIDI转按键自动化工具深度解析
  • 2026实验室用水配套选型参考,详解超纯水、纯化水设备选购要点及靠谱生产厂家推荐 - 栗子测评
  • 无感定位·智管全域:黎阳之光人员无感定位管理系统,重新定义安全与效率
  • 蚂蚁森林自动化收取:智能高效的能量管理解决方案
  • Agent 工具调用实战:从函数调用到可靠执行的设计方法
  • 3步快速上手BetterRenderDragon:解锁Minecraft极致画质的终极指南
  • 从照片到3D模型:手把手教你用Nerfstudio和COLMAP重建自己的小物件(含完整命令与避坑点)
  • 如何用RVC-WebUI在5分钟内实现专业级语音克隆
  • Llama3中文微调一站式工具包:51K指令数据+LoRA脚本+多精度量化模型
  • Linux 组调度的 idle_h_nr_running:空闲组任务数统计
  • Redis高可用面试知识:持久化+主从复制+哨兵机制
  • ComfyUI插件管理终极指南:如何3步搞定AI工作流扩展
  • 燕窝与鸡蛋进行对比
  • Windows风扇控制终极指南:5分钟掌握Fan Control专业散热管理
  • 区块链原理与技术:全系列持续更新
  • Obsidian Border主题:3个核心功能如何提升你的笔记效率?
  • MelonLoader终极指南:5分钟掌握Unity游戏模组安装技巧
  • 【AI工具与智能消息整合实战指南】:20年架构师亲授5大落地陷阱与避坑清单
  • 2026年6月谁家薄膜每平方米电弱点数试验仪质量好?用户真实体验与口碑榜单 - 品牌推荐大师1
  • 天津靠谱包包回收商家榜单,结合报价行情筛选优质变现门店! - 合扬奢侈品交易中心
  • PyPYLON技术解析:5个关键特性实现高效工业相机控制
  • 从零打造BB-8机器人:Arduino与3D打印实现球形驱动与磁耦合
  • 丹东市消防管漏水检测精准定位,厂区消防管网检测高效排查安全隐患 - 同城维修
  • Spark SQL详解(二):RDD转换DataFrame与Spark SQL读写数据库
  • 如何高效批量下载抖音直播回放:开源工具终极指南