第11章 需求预测与容量规划
未雨绸缪
章节导读
每年秋天,Google 的容量规划团队都会进行一场安静的战争:预测下一年全球用户会对 Google 的服务发起多少次请求,并据此决定要采购多少台服务器、在哪些数据中心部署、什么时候到位。这个决策的两端都是深渊——预测过低,服务会在流量高峰时过载,用户遭遇降级甚至宕机,错误预算被真实故障吞噬;预测过高,数亿美元的资金沉淀在闲置的机器上,机房空间、电力、冷却全部浪费。在 Google 的规模上,预测误差每偏差一个百分点,对应的都是天文数字的成本或风险。蓝皮书第 11 章讨论的就是这门「在不确定性中做资源决策」的工程学科:需求预测与容量规划。容量规划为什么难?因为它同时对抗三种不确定性。第一种是需求的不确定性:用户流量受季节(节假日购物季)、事件(突发新闻、病毒式传播)、产品动作(新功能上线、营销活动)多重因素驱动,历史规律只能部分外推未来。第二种是供给的不确定性:机器的采购有周期(下单到上架数周到数月)、机器的性能有差异(新旧机型混部)、机器的可用性有波动(故障率、维护窗口)——你以为有 1000 台机器,实际可用容量可能只有 850 台。第三种是系统行为的不确定性:同样的硬件,负载从 50% 升到 70% 时延迟可能平稳,升到 85% 时突然恶化——排队论告诉我们,利用率接近饱和时延迟非线性飙升,而「拐点在哪里」取决于代码版本、数据分布、依赖行为,且随时间漂移。容量规划的本质就是在这三重不确定性中做出「足够好」的决策:不追求精确(不可能),追求稳健(各种情况下都不至于灾难)。Google 的容量规划体系可以概括为一个循环:预测(Forecasting)→ 画像(Profiling)→ 规划(Planning)→ 验证(Testing)→ 执行与监控(Execution)。预测环节回答「未来需要多少服务能力」:基于历史时间序列(趋势、季节性、周期性)加业务输入(产品路线图、营销计划)生成需求预测,输出是未来各时间段的 QPS、存储量、带宽需求,且必须带置信区间——「下季度峰值 120 万 QPS,90% 置信区间 100 万到 150 万」比单点预测有用得多,因为规划决策需要知道不确定性的大小。画像环节回答「单位需求消耗多少资源」:这是 Google 容量规划最独特的概念——资源画像(resource profile)把「一次搜索请求」翻译成「多少 CPU 秒、多少内存、多少磁盘 IO、多少网络带宽」。有了画像,需求预测就能机械地转换为资源需求:120 万 QPS × 每请求 0.5 毫秒 CPU = 600 核 CPU。画像的维护是持续工程:代码优化会降低画像值(同样的请求消耗更少 CPU),新功能会抬高画像值,画像数据必须从生产环境持续采集(而非依赖过时的压测报告)。规划环节回答「资源怎么分布」:总量确定后,还要决定地理分布(哪些区域部署多少——就近服务用户且应对区域故障)、时间分布(何时采购何时上架——匹配需求增长曲线与供给周期)、冗余策略(N+1 还是 N+2?单机房故障时其余机房能否承接全部流量?)。Google 的原则是容量规划必须包含「故障冗余」:常态水位控制在 60% 到 70%,剩余空间既是增长缓冲也是故障缓冲——某个数据中心整体故障时,其流量要能被其他数据中心吸收而不引发连锁过载。验证环节回答「规划对不对」:负载测试(load testing)是容量数字的最终裁判——Google 会定期用真实流量的录制回放对生产系统做压测,验证「单实例安全容量」「集群拐点」「故障转移后的承载能力」这些规划依赖的关键数字。没有压测验证的容量模型只是数学练习。执行与监控环节回答「现实是否偏离计划」:容量水位持续监控(当前负载/安全容量的比值)、预测准确度回顾(实际流量 vs 预测值的偏差分析)、自动扩缩容作为短周期的执行手段(应对预测覆盖不了的日内波动)。这个循环的时间尺度是分层的:年度规划(数据中心建设、大额采购——周期以年计)、季度规划(机器采购与部署——周期以月计)、月度/周度调整(集群间容量调配)、日内自动扩缩(应对突发波动——周期以分钟计)。不同尺度用不同方法:年度看趋势和战略(业务增长模型),季度看时间序列预测,日内看实时指标驱动的自动伸缩。自动扩缩容(autoscaling)是现代容量规划的核心执行机制,分两种范式。响应式(reactive):基于当前指标(CPU 使用率、队列深度、请求延迟)触发扩容——优点是简单直接,缺点是有滞后:指标超标才开始扩,扩容完成前用户已经在受苦;对突发流量(秒级翻倍)响应式扩容永远慢半拍。预测式(predictive):基于预测的未来负载提前扩容——优点是能赶在需求到来前就绪,缺点依赖预测质量(预测错了就是浪费或不足)。成熟系统是两者混合:预测式做基线(按预测曲线提前布置容量),响应式做修正(实际偏离预测时快速补偿)。Kubernetes 的 HPA(水平扩缩,按指标调副本数)加 CronHPA(按时间表扩缩)加 KEDA(按事件源扩缩)的组合就是这种混合架构的实现。扩缩容的工程细节充满陷阱:扩容快缩容慢(缩容太激进会在波动中反复震荡,需要稳定窗口和冷却期);新实例的冷启动成本(缓存预热、连接建立、JIT 编译——没有慢启动保护,扩容本身会造成延迟尖峰);扩容的天花板(依赖的数据库连接池、下游服务容量、云厂商配额——扩了应用层发现瓶颈在数据层,容量规划必须是全链路的);以及缩容的排空(drain:优雅终止存量请求再下线实例)。容量规划与成本优化是一体两面。Google 的洞察是:容量规划的产出不仅是「买多少机器」,还包括「机器的性价比管理」——批处理任务用抢占式资源(Borg 的混合部署:在线服务与批处理共享机器,批处理填充在线服务的空闲容量,机器利用率从 30% 提到 60% 以上);不同优先级的负载用不同等级的资源;预测的低谷期主动缩容并把资源让给离线任务。成本优化的度量单位是「单位业务成本的资源消耗」(每千次请求的 CPU 秒、每 GB 存储的月成本),它的持续下降来自三个引擎:画像优化(代码性能改进)、利用率提升(混部与自动伸缩)、采购策略(机型选择与预留实例)。对大多数组织,容量规划的起点不需要 Google 的复杂度,但需要 Google 的纪律:知道自己的单实例安全容量(压测得出,而非猜测)、知道当前水位(实时监控)、知道增长趋势(哪怕只是简单的线性外推)、知道扩容的提前量(从决定到容量就绪要多久)。这四个「知道」构成容量规划的最小闭环,缺失任何一个,你的系统都在裸奔——增长会突然撞上容量墙,或者钱包会悄悄被闲置资源掏空。本章接下来的内容将深入每个环节:时间序列预测的方法与陷阱、资源画像的采集与使用、从预测到采购的规划流程、缓冲与冗余的设计原则、响应式与预测式扩缩容的工程实现、以及容量与成本的联合优化。
核心概念
- 时间序列预测
- 资源画像
- 容量缓冲
- 自动扩缩容
要点精析
需求预测的方法体系:从移动平均到增长模型。需求预测是容量规划的输入端,方法按时间尺度和数据特征分层。短期预测(日内到周)用时间序列方法:移动平均(MA)平滑噪音捕捉近期水平;指数平滑(ETS)给近期数据更高权重,Holt-Winters 三参数指数平滑同时建模水平、趋势、季节性——对「工作日高周末低、白天高深夜低」的互联网流量拟合效果好;ARIMA/SARIMA 建模自相关结构,适合规律性强的负载。这些方法的共同前提是「未来是过去的延续」,对稳态业务准确,对突变(新功能爆火、营销活动)失效——所以短期预测必须叠加业务日历(已知的活动、发布计划作为外生变量)。中期预测(季度)用趋势外推加业务输入:线性或指数增长模型拟合历史趋势,再与产品团队对齐路线图(「下季度上线视频功能,预计带来 30% 流量增长」——这类业务输入比任何统计模型都重要,因为统计模型看不见未来)。长期预测(年度)用增长模型与渗透率分析:用户数增长曲线(S 型渗透曲线)、单用户行为强度变化(人均请求数)、新市场扩张——长期预测的误差范围极大,其价值不在精确而在「量级判断」:明年需要的是多一个机架还是多一个数据中心。预测质量的度量必须制度化:MAPE(平均绝对百分比误差)按周回顾,且分维度拆解——整体误差 10% 可能是「平时 5% 加峰值日 40%」的混合,而容量规划恰恰败在峰值日;预测偏差的分布同样重要:系统性低估(连续多周实际高于预测)说明模型漏掉了增长因素,比随机误差危险得多。Google 的实践要点:预测永远带置信区间而非单点值,规划决策用区间的不同分位数(常态容量用 P50,冗余容量用 P90,采购决策用 P95——宁可略多买也不要峰值日宕机);预测模型定期重训练(流量模式会漂移,一年前训练的模型对今天的预测可能系统性偏差);以及最重要的——预测错误的代价不对称性要显式建模:低估导致过载(用户伤害加紧急采购的溢价),高估导致闲置(资金占用),两者的成本比决定你应该偏向保守还是激进,大多数在线服务的答案是「宁可高估 10% 也不要低估 5%」。
季节性、事件驱动与突发需求:预测的三类挑战。真实流量的时间结构分三类,各有不同的应对策略。第一类,规律季节性:日周期(白天高峰深夜低谷,振幅可达 3 到 5 倍)、周周期(工作日与周末模式不同,B2B 服务周末流量可能只有工作日的 20%,而娱乐服务相反)、年周期(电商的节假日购物季、税务服务的报税期、教育服务的开学季)。规律季节性是可预测的,Holt-Winters 或 SARIMA 能很好地建模,规划上用「同时段历史对比」做基线(本周三下午 3 点的容量需求参照过去四周三下午 3 点的均值加趋势修正)。第二类,事件驱动需求:可预知事件(产品发布会、营销大促、体育赛事直播、选举夜)和不可预知事件(突发新闻、病毒式传播、名人事件)。可预知事件的处理是「事件日历制度」:产品、市场、运营团队的活动计划提前录入容量日历,SRE 按事件类型估算流量放大系数(历史同类事件的数据:上次发布会带来 8 倍峰值流量)并提前扩容——放大系数的估算宁可保守偏高,事件日的容量闲置成本远低于容量不足成本。不可预知事件无法预测,只能靠架构韧性应对:自动扩缩容的快速通道(分钟级扩容能力)、过载保护(第 6 章的降级与负载削减是突发流量的最后防线)、以及「弹性容量池」(云上预留的快速扩容配额——平时不用,突发时分钟级拉起)。第三类,结构性突变:产品改版(新首页自动刷新使请求量翻倍)、客户端行为变化(App 新版本的重试策略 bug 造成流量放大)、爬虫与攻击流量。突变对预测模型是毒药——历史数据与未来彻底脱节,任何统计方法都失效。应对是「突变检测加人工介入」:实时监控「实际 vs 预测」的偏差率,偏差超过阈值(如 30%)自动告警,SRE 与产品团队快速定位原因(是新功能上线?是爬虫?是攻击?),确认后更新预测基线。Google 的经验:结构性突变的定位速度决定容量事故的持续时间——「流量为什么翻倍」这个问题应该能在 30 分钟内回答,回答不了说明变更管理与流量分析工具存在盲区。三类挑战的共同教训:预测模型只是容量规划的起点,人的业务理解(事件日历、突变诊断)与系统的架构韧性(自动扩容、过载保护)是预测失效时的两道保险。
资源画像:把业务需求翻译成资源语言。资源画像(resource profiling)回答一个看似简单实则关键的问题:处理一个单位的业务请求,消耗多少资源?形式化表达:每请求 CPU 秒数、每请求内存字节、每请求磁盘 IO 次数、每请求网络字节数。有了画像,容量规划变成机械换算:预测的 QPS × 每请求 CPU = 需要的 CPU 核数,再除以单核安全利用率就是需要的机器数。画像的采集方法按精度递增:粗粒度用「总量除法」——集群总 CPU 消耗除以总请求数,简单但被后台任务、批处理、空闲开销污染;中粒度用「负载对比法」——在不同负载水平(30%、50%、70%)下测量资源消耗,线性回归得出边际成本(每增加一个 QPS 增加多少 CPU)和固定成本(与负载无关的基础消耗),这个方法能分离「服务请求的成本」与「维持服务的成本」;细粒度用「请求级追踪」——分布式追踪系统记录每类请求的实际资源消耗(不同 API 的画像差异可能达百倍:缓存命中的读请求 0.1ms CPU,复杂聚合查询 50ms CPU),按请求类型分别画像。画像的使用要点。第一,画像必须分请求类型:用「平均画像」规划混合负载会在请求构成变化时严重失准——某 API 占比从 10% 升到 30%,总请求数没变但 CPU 需求可能翻倍。第二,画像必须持续更新:代码优化、数据规模增长(索引变大、缓存命中率变化)、依赖变更都会让画像漂移,Google 的做法是画像数据从生产持续采集、按月回顾趋势——画像值的突然变化本身是信号(可能是性能回归,也可能是缓存失效)。第三,画像要包含「非线性区」:资源消耗与负载不是全程线性——接近饱和时,上下文切换、锁竞争、GC 压力让单位成本上升,画像模型应该标注「线性区上限」(通常是安全水位的 70%),超过后按非线性系数放大。第四,画像驱动优化优先级:「高画像值 × 高流量」的接口是性能优化的黄金目标——优化 10% 的画像值等于免费扩容 10%,这比买机器便宜得多。画像体系的成熟度标志:新服务上线前就能给出画像估算(基于同类服务加架构评审),压测验证后修正;容量讨论从「我们需要更多机器」变成「我们的每请求成本是多少、能降到多少」——资源画像把容量规划从采购问题转化为工程问题。
从预测到采购:容量规划的完整流程。Google 的容量规划流程是一条从需求预测到机器上架的完整流水线,各环节的衔接质量决定整体效果。环节一,需求汇总:各产品团队提交未来 4 到 6 个季度的容量需求(基于业务预测加资源画像换算),格式标准化——服务名、预期 QPS 曲线(分位数形式)、资源需求(CPU/内存/存储/带宽)、地理分布要求、优先级(P0 核心服务到 P2 可延迟服务)。环节二,容量核算:基础设施团队核算现有容量的「真实可用量」——名义容量(机器总数)减去故障冗余(N+1 策略预留)、减去维护窗口占用(滚动升级期间部分容量不可用)、减去碎片化损失(大规格任务放不进小空隙);真实可用量与需求的差距就是净需求。环节三,规划决策:净需求的满足方式按时序分层——近期(本季度)用存量调配(从低优先级服务借容量、跨区域调度)、中期(2 到 3 季度)用采购(下单到上架的周期倒排)、长期用基础设施建设(新数据中心的选址与建设周期以年计);决策输出是采购计划:机型、数量、到货时间、部署位置。环节四,供给管理:采购计划执行中的风险管理——供应链延迟(芯片短缺、物流问题)的缓冲策略(提前量加多供应商)、到货机器的验收与部署自动化(上架、烧机测试、入池的流水线)。环节五,回顾闭环:每季度对比「预测 vs 实际」「计划 vs 执行」,偏差分析驱动流程改进——预测系统性偏差修正模型,采购延迟调整提前量,画像漂移触发重新压测。这条流水线的时间纪律至关重要:每个环节有明确的截止点和交付物(需求汇总在季度开始前 8 周完成、采购决策在 6 周前敲定),因为硬件供给周期是刚性的——错过决策窗口,需求到来时机器还在海上。中小组织的简化版本:月度容量评审会(30 分钟)过三张表——当前水位表(各服务负载/安全容量)、预测表(未来 3 个月需求曲线)、行动表(扩容计划与负责人);核心纪律不变:水位超过 70% 必须有扩容行动、扩容提前量必须大于供给周期(云环境是小时级,自建机房是月级)。流程的价值不在复杂度而在「确定性」:每个参与者知道什么时候要交什么、决策依据是什么、延误的后果是什么——容量事故的大多数根源不是预测失败,而是流程断裂(预测做了没人看、看了没决策、决策了没执行)。
容量缓冲与冗余设计:为不确定性定价。容量缓冲(headroom)是规划容量与实际可用容量之间刻意保留的空隙,它同时服务三个目的:吸收预测误差(实际需求超过预测时的缓冲)、承接故障转移(某节点/机房故障时其流量需要被剩余容量吸收)、容纳增长波动(两次扩容之间的自然增长)。缓冲设计的第一原则是「故障驱动」:缓冲量不是拍脑袋的百分比,而是由故障场景倒推——「单机房故障时,剩余机房必须能承接全部流量且水位不超过安全线」意味着 N 个机房的常态水位上限是 (N-1)/N × 安全水位:3 个机房、安全水位 80%,常态水位就不能超过 53%;这就是为什么 Google 的常态水位控制在 60% 到 70%——它不是浪费,是故障冗余的价格。缓冲设计的第二原则是「分层」:不同时间尺度的波动用不同层次的缓冲吸收——秒级波动靠单机队列和自动限流、分钟级波动靠响应式自动扩容、小时级波动靠预测式扩容、天级以上的增长靠采购计划;每层缓冲的成本不同(队列免费、自动扩容低成本、预留机器高成本),好的设计让便宜的缓冲处理高频小波动,贵的缓冲只应对低频大波动。第三原则是「缓冲也要监控」:缓冲消耗速度是比绝对水位更早的告警信号——水位从 50% 到 65% 用了三天(正常增长)与用了三小时(异常流量)需要完全不同的响应;为「缓冲消耗速率」设置告警(如 24 小时内水位上升超过 10 个百分点)能比「水位超阈值」告警早得多发现问题。冗余与缓冲的区别值得澄清:冗余是「多出来的完整副本」(N+1 的备用机房、备用数据库),缓冲是「现有副本里的空闲容量」;冗余应对「整体失效」,缓冲应对「负载超出预期」——两者都需要,且冗余的有效性依赖缓冲(备用机房若常态满载,故障切换过去等于把过载转移)。Google 的特殊策略是「用批处理填充缓冲」:在线服务预留的缓冲容量在空闲时借给批处理任务(Borg 的混部),批处理任务可被随时抢占(preemption)——在线流量上涨时秒级收回容量。这个设计把缓冲的机会成本降到接近零,是超大规模基础设施的独特优势;中小组织在云上的对应物是「用可抢占实例(spot/preemptible)填充非关键负载」,同样能摊薄冗余成本。缓冲量的年度复审同样重要:架构改进(性能优化降低画像值)、依赖变化(新的强依赖引入新的故障场景)、业务变化(峰值模式改变)都要求缓冲策略跟着演进——去年的正确缓冲量可能是今年的浪费或不足。
响应式与预测式自动扩缩容:工程实现与陷阱。自动扩缩容是容量规划的「短周期执行器」,两种范式各有适用域。响应式扩缩容(reactive):监控指标(CPU、内存、队列深度、自定义 SLI)超过阈值即扩容、低于阈值即缩容。Kubernetes HPA 是标准实现,其工程细节决定成败:指标选择上,CPU 使用率是默认但常非最优——IO 密集型服务 CPU 低但已饱和,更好的指标是「活跃请求数/实例」或队列深度,甚至直接用 SLI(P99 延迟超标即扩容——「以用户体验为目标的扩缩容」);阈值设定上,扩容阈值应显著低于「性能拐点」(CPU 70% 扩容而非 90%,因为扩容生效需要时间,等指标到 90% 再扩用户已经在受苦);稳定窗口上,扩容要快(默认 0 秒冷却,流量上涨不等人)、缩容要慢(默认 5 分钟稳定窗口,防止波动中反复震荡——缩容震荡的代价是实例反复创建销毁加缓存反复失效);行为配置上,HPA 的 behavior 字段可限制扩缩速率(每 60 秒最多翻倍/最多缩 10%),防止过度反应。预测式扩缩容(predictive):按预测的负载曲线提前扩容——CronHPA(时间表驱动:每天 8 点扩到 20 副本)、或机器学习预测驱动的扩容。适用场景:负载有强规律性(日周期明显的业务)、扩容前置时间长(大内存实例启动加预热需要 10 分钟,响应式来不及)、已知事件(大促日历)。预测式的风险是预测失效:预测高了浪费、预测低了不足——所以预测式永远与响应式叠加(预测做基线,响应式做实时修正),而非替代。混合架构的标准形态:CronHPA 按日周期曲线设置每时段的最小副本数(基线),HPA 在基线之上按实时指标弹性调整(修正),两者取最大值生效。扩缩容的四个经典陷阱。陷阱一,冷启动伤害:新实例缓存空、连接池空、JIT 未热,立即接全量流量会延迟尖峰——解法是慢启动(负载均衡权重渐进爬升,见第 9 章)加预热流量。陷阱二,全链路瓶颈转移:应用层扩容后发现数据库连接池耗尽——扩容规划必须覆盖全链路(应用、缓存、数据库、消息队列的容量联动),单点扩容只是把瓶颈搬家。陷阱三,缩容排空不当:直接杀实例导致存量请求失败——必须优雅终止(停止接新请求、等待存量完成、超时强制),Kubernetes 的 preStop hook 加 terminationGracePeriodSeconds 是标准机制。陷阱四,配额天花板:云厂商的实例配额、区域库存不足——扩容失败在最需要的时候发生,配额要按「峰值需求 × 1.5」预先申请并定期复审,多云/多区域部署是库存风险的终极对冲。
容量规划与成本优化:单位成本工程。容量规划做到成熟阶段,必然与成本优化合流——因为两者的核心变量相同:资源画像(单位业务成本的资源消耗)与利用率(已购资源的产出效率)。成本优化的三个引擎。引擎一,画像优化(降低单位成本):性能工程直接降低每请求资源消耗——代码优化(算法复杂度、内存分配)、缓存策略(命中率每提升 1%,回源成本下降一截)、存储压缩与分层(热数据 SSD、温数据 HDD、冷数据归档)。度量单位是「每千请求 CPU 秒」「每 GB 有效存储成本」的月度趋势,这个趋势线是性能团队最诚实的 KPI——Google 的经验是持续的画像优化能带来每年 20% 到 30% 的单位成本下降,复利效应远超一次性架构重构。引擎二,利用率提升(摊薄固定成本):在线服务的常态利用率通常只有 20% 到 40%(峰值容量加缓冲的代价),提升手段包括混部(在线服务与批处理/离线任务共享机器,批处理填充波谷——Google Borg 的核心设计,利用率可提到 60% 以上)、潮汐调度(不同时区/不同业务模式的服务共享资源池:白天给 B2B 服务、晚上给批处理)、可抢占实例(非关键负载用 spot 实例,成本是按需实例的 1/3 到 1/5)。引擎三,采购与供给策略(降低资源单价):云上的预留实例/Savings Plans(承诺 1 到 3 年用量换 30% 到 70% 折扣——本质是把弹性换成折扣,适合稳定的基线负载;波动部分用按需加 spot 的组合)、机型选择(新一代机型性价比通常高 20% 到 40%,滚动换代是持续动作)、多区域比价(同配置在不同区域价差可达 30%)。成本优化的决策框架是「基线加弹性」分层:稳定基线负载(历史 P10 水位)用预留/自建(最便宜),日常波动(P10 到 P90)用按需实例(中等成本),突发峰值(P90 以上)用 spot 加自动扩容(弹性优先)——这个分层把「为峰值买单」转化为「为峰值租用」。成本可见性是优化的前提:按服务/团队分摊的资源账单(showback/chargeback)、单位业务成本仪表盘(每次订单的基础设施成本)、闲置资源检测(利用率低于 5% 的实例、无流量的负载均衡器、孤儿磁盘)——看不见的成本无法优化。最后一个平衡提醒:成本优化与可靠性存在张力(混部增加干扰风险、spot 实例随时被回收、预留降低架构灵活性),优化的边界是 SLO——任何成本措施上线前都要回答「它如何影响错误预算」,用混沌实验验证(杀掉 spot 实例、模拟混部干扰)而非假设无害。
负载测试:容量数字的最终裁判。容量规划依赖的所有关键数字——单实例安全容量、集群拐点、故障转移承载能力、扩容生效时间——都必须经过负载测试(load testing)验证,未经压测的容量模型只是愿望。负载测试的四种类型各有目的。基准测试(benchmark):测量单实例在不同负载水平的性能曲线——梯度加压(从 10% 到 150% 预估容量,每级持续足够长达到稳态),记录每级的 P50/P95/P99 延迟、错误率、资源使用率,产出三个关键数字:拐点(延迟开始非线性上升的负载)、崩溃点(错误率超 5%)、安全容量(拐点的 70%,作为规划依据)。负载测试(load test):验证集群在预期峰值负载下的表现——用预测的峰值 QPS(如 P95 分位)打压全集群,验证 SLO 是否达成、瓶颈在哪个组件。压力测试(stress test):找到系统的真实极限并观察失败模式——持续加压直到崩溃,重点不是崩溃点数字而是「崩溃的方式」:是优雅降级(限流生效、核心功能保留)还是雪崩(级联失败、恢复缓慢)?崩溃后流量回落,系统能否自愈?浸泡测试(soak test):长时间(数小时到数天)中等负载运行,发现慢性问题——内存泄漏、连接泄漏、日志膨胀、缓存碎片。压测的方法论要点。第一,流量真实性:压测流量的请求分布必须模拟生产(读写比例、参数多样性、用户行为模式)——用生产流量录制回放(Google 的做法)远好于合成的均匀请求;特别警惕缓存命中率失真:压测的重复请求让缓存命中率虚高,测出的容量偏乐观,要用与生产一致的键空间分布。第二,环境代表性:压测环境与生产的差异(机器规格、数据规模、依赖 mock)会让结论失效——数据规模尤其关键(1 万条记录的数据库与 10 亿条的查询性能完全不同),理想是在生产环境的隔离切片上压测(影子流量)。第三,全链路视角:单服务压测发现不了链路瓶颈(应用层容量充足但数据库连接池只有 100),压测应该覆盖完整调用链,观察每一跳的水位。第四,常态化:容量数字会漂移(代码变更、数据增长、依赖变化),Google 定期(季度级)对核心服务重跑压测更新容量基线,重大变更后触发增量压测——「上次压测是两年前」的容量数字等于没有数字。压测的组织实践:压测计划要评审(目标、流量模型、中止条件——压测本身也可能打挂共享依赖)、压测窗口要协调(避开业务高峰、通知相关团队)、压测报告要归档(容量基线的版本历史)。
容量规划的常见失败模式与反模式。失败模式一,「鸵鸟式规划」:没有容量数据也没有预测,靠「出事了再加机器」——响应式救火在云环境尚可苟活(分钟级扩容),在自建环境必然周期性撞墙(采购周期数月,增长不等人)。矫正:建立最小容量闭环(水位监控加月度评审),哪怕预测只是简单趋势外推。失败模式二,「静态容量数字」:两年前压测得出的「单实例 1000 QPS」被写进文档奉为圭臬,期间代码重构了三次、数据量涨了十倍——真实容量可能只剩 400。矫正:容量数字带「测量日期」属性,超过两个季度自动标记过期,重大变更后强制重测。失败模式三,「平均数陷阱」:用平均负载规划容量——平均水位 40% 看似安全,但日内峰值达到 95%(每天中午用户都在超时)。矫正:容量规划一律用分位数(P95/P99 峰值)而非均值,且分时段建模。失败模式四,「单点画像」:所有请求按同一画像计算,实际请求构成变化后容量模型全面失准——新上线的富媒体 API 单请求成本是老 API 的 50 倍,占比 5% 就吃掉了 20% 的容量。矫正:画像按请求类型细分,监控请求构成的漂移。失败模式五,「扩容幻觉」:以为扩容能解决一切,实际瓶颈在不可水平扩展的组件(单主数据库、分布式锁、第三方 API 配额)——应用层扩到 100 副本,数据库连接池 200 个连接成为硬顶。矫正:容量规划覆盖全链路,识别「不可扩展点」并单独规划(垂直扩容、分片、缓存前置)。失败模式六,「缓冲侵蚀」:预算压力下反复削减冗余——「水位 75% 也还好吧」逐步变成 85%、90%,直到某次单机房故障时剩余容量承接不住,缓冲侵蚀的账单一次性到期。矫正:缓冲水位红线制度化(写入容量政策,突破需要显式审批与风险签署),并用故障演练验证缓冲的真实有效性(第 10 章的混沌实验:切走一个机房流量,观察剩余机房水位)。失败模式七,「预测与业务脱节」:SRE 用纯统计模型预测,产品团队下个月的营销活动、新功能发布一无所知——统计模型对结构性变化天然失明。矫正:事件日历制度(业务活动提前录入)加预测偏差的双向沟通(SRE 向业务同步预测,业务向 SRE 同步计划)。这些失败模式的共同根源是把容量规划当「一次性计算」而非「持续运营的系统」——容量规划的健康标志是:数字新鲜(定期重测)、假设显式(画像与缓冲的依据可追溯)、流程闭环(预测-规划-验证-回顾)、与业务同步(事件日历与增长对齐)。
云时代的容量规划:从采购到租用的范式转移。云环境把容量规划的核心动作从「采购硬件」变成「管理配额与成本」,但规划的纪律不减反增。范式差异一,供给弹性改变时间尺度:自建环境的扩容提前量以月计(采购、上架、部署),云环境以分钟计(API 调用即扩容)——这似乎让长期预测变得不重要,实则不然:弹性有天花板(云厂商的区域库存、账户配额、大规模扩容的速率限制),2020 年疫情初期多家云服务商在特定区域的特定机型出现库存不足,依赖「随时能扩」的组织被迫紧急迁移——云上的容量规划从「预测需求」转向「预测需求 + 保障供给确定性」(配额预申请、多可用区/多区域布局、关键机型库存的持续验证)。范式差异二,成本模型从资本支出到运营支出:自建是「买了机器闲置也闲置」(沉没成本),云是「开着实例就在烧钱」(实时成本)——这让利用率优化的价值放大(闲置实例每天都在产生真实账单),也让自动缩容从「可选优化」变成「成本刚需」;同时预留实例的决策本质是「用承诺换折扣」的金融决策,需要基于负载基线的稳定性分析(P10 水位以下的负载足够稳定,值得预留覆盖)。范式差异三,容量单位的抽象化:Serverless(按请求计费、平台自动伸缩)把容量规划推给云厂商,但新的规划对象出现——并发限制(Lambda 的账户级并发配额)、冷启动比例(预留并发 vs 按需并发的权衡)、下游容量(函数无限伸缩但数据库连接有限——Serverless 的弹性会更快撞上下游瓶颈)。范式差异四,多租户干扰的不确定性:云上的「邻居噪音」(共享宿主机的资源竞争)让性能基线有波动,容量数字需要更大的安全边际,关键服务考虑专属实例/裸金属。云上容量规划的实践清单:配额管理台账(每区域每机型的配额、当前使用、峰值需求、余量告警);成本异常检测(日账单突变告警——扩容 bug 或攻击流量的信号);弹性演练(定期验证「从当前规模扩到 2 倍需要多久、会不会撞配额」——没演练过的弹性是假弹性);退出策略评估(对云厂商的依赖深度、迁移成本——容量规划的最高层次是选择权管理)。核心认知:云没有消灭容量规划,它消灭的是「容量规划 = 买机器」的狭隘等式——预测、画像、缓冲、验证的方法论原封不动,执行手段从采购单变成了 API 调用和账单管理。
代码示例
/* 示例 1:时间序列需求预测(Python,Holt-Winters + 线性趋势) */
import numpy as np
from statsmodels.tsa.holtwinters import ExponentialSmoothing
def forecast_demand(history, periods_ahead=28, season_len=7):
"""history: 按天的历史 QPS 峰值序列(至少 3 个季节周期)"""
/* Holt-Winters 三参数指数平滑:水平 + 趋势 + 周季节性 */
model = ExponentialSmoothing(
history,
trend="add", /* 加法趋势:增长量恒定 */
seasonal="add", /* 加法季节性:峰谷差恒定 */
seasonal_periods=season_len,
).fit(optimized=True)
point_forecast = model.forecast(periods_ahead)
/* 用残差的标准差构造置信区间(预测必须带不确定性) */
residuals = history - model.fittedvalues
sigma = np.std(residuals)
return {
"p50": point_forecast, /* 常态容量规划用 */
"p90": point_forecast + 1.28 * sigma, /* 冗余容量用 */
"p95": point_forecast + 1.65 * sigma, /* 采购决策用 */
}
def detect_forecast_drift(actual, predicted, threshold=0.3):
"""实际与预测偏差超阈值 -> 结构性突变告警"""
deviation = (actual - predicted) / max(predicted, 1)
if abs(deviation) > threshold:
alert("流量偏离预测 " + str(round(deviation * 100)) +
"%,排查:新功能?爬虫?攻击?营销活动?")
return deviation
/* 预测质量周度回顾:MAPE 分维度拆解 */
def mape(actual, predicted):
return np.mean(np.abs((actual - predicted) / actual)) * 100
/* 整体 MAPE 之外,必须单独看峰值日 MAPE——容量败在峰值 */这段代码实现了需求预测的三个工程要点。第一,模型选择与配置:Holt-Winters 的加法趋势加加法季节性适合互联网流量的典型形态(稳定的日/周周期加近似线性的增长);season_len=7 建模周周期,如果有充足的小时级数据可以用 24 或 168 建模日周期。trend 和 seasonal 的「加法 vs 乘法」选择取决于波动是否随水平放大:流量越大峰谷差越大(常见于增长期业务)用乘法,峰谷差恒定用加法——用 AIC/BIC 对比两种配置的拟合优度是标准做法。第二,也是最重要的——预测输出是分位数而非单点:p50 用于常态容量(一半时间够用),p90 用于冗余设计,p95 用于采购决策(宁可略多买)。置信区间用残差标准差构造是最简方法,更严谨的做法是 bootstrap 残差重采样或模型原生的预测区间。这个设计直接对应「预测错误的代价不对称」:低估导致过载的代价远大于高估导致闲置,所以关键决策用高分位数。第三,drift 检测把预测从「一次性计算」变成「持续监控」:实际流量偏离预测 30% 即告警,触发人工诊断——统计模型对结构性突变(新功能、爬虫、攻击)天然失明,人的业务理解是不可替代的补充。MAPE 的周度回顾要分维度:整体误差可能掩盖「平时准、峰值日不准」的致命模式,而容量规划恰恰败在峰值日;如果峰值日 MAPE 持续高于 30%,说明事件日历和放大系数估算需要改进。数据准备的一个细节:history 应该用「每日峰值 QPS」而非日均值——容量为峰值而规划,用均值训练模型会系统性低估需求。/* 示例 2:资源画像计算(负载对比法,Python 风格) */
import numpy as np
def build_resource_profile(load_test_results):
"""
load_test_results: 压测数据列表
每项 = {"qps": 负载水平, "cpu_cores": 总CPU消耗(核),
"mem_gb": 内存(GB), "request_mix": 请求构成}
线性回归: CPU = 固定成本 + 边际成本 * QPS
"""
qps = np.array([r["qps"] for r in load_test_results])
cpu = np.array([r["cpu_cores"] for r in load_test_results])
/* 最小二乘拟合 y = a + b*x */
marginal_cost, fixed_cost = np.polyfit(qps, cpu, 1)
/* 边际成本 b = 每 QPS 的 CPU 核数(每请求 CPU 秒 = b) */
/* 固定成本 a = 与负载无关的基础消耗(后台任务、心跳、空闲开销) */
return {
"cpu_seconds_per_request": marginal_cost,
"fixed_cpu_cores": fixed_cost,
"linear_range_qps": detect_knee(qps, cpu), /* 线性区上限 */
}
def capacity_from_profile(profile, target_qps, safe_util=0.7,
core_per_machine=32):
"""从画像换算机器数:需求 CPU / (单核 * 安全利用率) / 每机核数"""
required_cores = (profile["fixed_cpu_cores"]
+ profile["cpu_seconds_per_request"] * target_qps)
usable_cores_per_machine = core_per_machine * safe_util
machines = required_cores / usable_cores_per_machine
return {
"required_cores": round(required_cores, 1),
"machines": int(np.ceil(machines)),
/* N+1 冗余:单机房故障时其余机房可承接 */
"machines_with_n1": int(np.ceil(machines * 3 / 2)),
}
/* 例:画像 = 每请求 0.8ms CPU(0.0008 核秒),固定 20 核
目标 50 万 QPS:需要 20 + 400 = 420 核
32 核机器 @ 70% 安全利用率 = 22.4 可用核/台 -> 19 台
N+1 冗余(3 机房挂 1)-> 28 台 */资源画像是把「业务需求」翻译成「资源语言」的转换器,这段代码展示了负载对比法的完整实现。核心思想是线性分解:总 CPU = 固定成本 + 边际成本 × QPS。固定成本(截距 a)是与负载无关的消耗——后台线程、心跳、监控采集、JVM 基础开销;边际成本(斜率 b)才是「每请求的真实成本」。分离两者的实践价值:固定成本高的服务不适合缩到很少实例(每台机器都要付固定成本,实例越少总固定开销占比越高);边际成本是性能优化的靶子(优化代码降低 b,等于免费扩容)。detect_knee 检测线性区上限至关重要:负载接近饱和时,锁竞争、GC、上下文切换让单位成本非线性上升,画像模型必须标注「这个线性公式在多少 QPS 以内有效」——超出线性区还用线性公式外推,容量会系统性低估。capacity_from_profile 的换算链条展示了规划数字的生成逻辑:需求 QPS → 需求核数(画像换算)→ 机器数(除以单机可用核)→ 冗余机器数(N+1 策略)。safe_util=0.7 是安全水位线(对应排队论的拐点前区域),N+1 的 3/2 系数对应「3 机房挂 1 个,剩余 2 个要承接 3 个的负载」——冗余系数由故障策略决定而非拍脑袋。画像的使用纪律:按请求类型分别画像(读请求 0.2ms、写请求 2ms、聚合查询 20ms——混合负载按构成加权,构成变化时重新加权);画像数据带测量日期(代码变更后画像漂移,超过一季度或重大版本后必须重测);生产画像与压测画像交叉验证(用生产的「总 CPU/总请求数」粗算对比压测回归结果,偏差大说明压测流量模型失真)。这个模型的输出直接接入采购流程:machines_with_n1 减去现有机器数就是净需求,乘以交付周期倒排就是下单时间——从画像到采购的每一步都是可审计的计算,这正是容量规划工程化的意义。/* 示例 3:Kubernetes HPA 配置(响应式扩缩容 + 行为控制) */
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-server-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
minReplicas: 6 /* 基线:预测的低谷容量 + N+1 冗余 */
maxReplicas: 60 /* 天花板:全链路压测验证过的下游承载上限 */
metrics:
/* 主指标:每 Pod 活跃请求数(比 CPU 更贴近饱和度的信号) */
- type: Pods
pods:
metric: { name: http_requests_in_flight }
target: { type: AverageValue, averageValue: "80" }
/* 辅指标:CPU 兜底(自定义指标失效时的保护) */
- type: Resource
resource:
name: cpu
target: { type: Utilization, averageUtilization: 70 }
behavior:
scaleUp:
stabilizationWindowSeconds: 0 /* 扩容零等待:流量上涨不等人 */
policies:
- type: Percent
value: 100 /* 每 30 秒最多翻倍 */
periodSeconds: 30
- type: Pods
value: 4 /* 或每 30 秒最多加 4 个(取大者) */
periodSeconds: 30
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300 /* 缩容等 5 分钟稳定窗口,防震荡 */
policies:
- type: Percent
value: 10 /* 每 60 秒最多缩 10%:缓慢释放 */
periodSeconds: 60
---
/* 预测式基线:CronHPA 风格的定时最小副本(与 HPA 取最大值) */
/* 工作日 08:30 提前扩到 20 副本迎接早高峰,23:00 回落 */
cron_jobs:
- schedule: "30 8 * * 1-5"
target_min_replicas: 20
- schedule: "0 23 * * *"
target_min_replicas: 6这份 HPA 配置是「响应式为主、预测式做基线」混合架构的标准实现,每个参数都有明确的工程理由。指标选择上,主指标用 http_requests_in_flight(每 Pod 活跃请求数)而非 CPU:活跃请求数是饱和度的直接信号(请求在实例内排队即接近饱和),且对 IO 密集型服务比 CPU 灵敏得多(CPU 40% 时线程池可能已耗尽);target 80 的设定依据是压测——单实例在 80 并发请求内 P99 保持 SLO 内,超过即进入性能拐点区。CPU 70% 作为辅指标兜底:自定义指标采集故障时(exporter 挂了),HPA 退化为 CPU 驱动仍能工作——扩缩容机制自身的容错常被忽视。maxReplicas: 60 不是随便填的大数:它是全链路压测验证过的上限——超过 60 副本,数据库连接池或下游服务会成为瓶颈,扩容反而制造故障(瓶颈转移加连接风暴);「扩容的天花板由最弱一环决定」必须写进配置注释。behavior 是 HPA v2 的精髓,实现「扩容快、缩容慢」的不对称策略:scaleUp 稳定窗口 0 秒(指标超标立即行动)且每 30 秒可翻倍(应对突发流量的指数追赶);scaleDown 稳定窗口 300 秒(指标回落后观察 5 分钟才动手,防止波动中反复扩缩)且每 60 秒最多缩 10%(缓慢释放,给流量回升留余地)。缩容震荡的代价真实而昂贵:实例销毁重建的成本、缓存冷启动的延迟尖峰、连接池的反复冲击——慢缩容用少量冗余成本换取稳定性。CronHPA 部分实现预测式基线:工作日 08:30 提前把 minReplicas 提到 20——早高峰的负载曲线高度规律,等指标超标再扩(响应式)意味着高峰期前几分钟用户已经在排队,提前 30 分钟布置容量让高峰无感通过;HPA 与 CronHPA 取最大值生效,预测失效时响应式兜底、预测生效时省去追赶时间。minReplicas: 6 的构成也值得注释:预测低谷负载需要 4 副本,N+1 冗余加 2——最小值同样是算出来的,不是「感觉 6 个差不多」。/* 示例 4:Kubernetes VPA 配置与资源画像自动化(YAML) */
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-server-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
updatePolicy:
updateMode: "Off" /* 关键:只推荐不执行,人工审核后落地 */
resourcePolicy:
containerPolicies:
- containerName: api-server
minAllowed:
cpu: 500m
memory: 1Gi
maxAllowed:
cpu: 8 /* 防止推荐值失控(异常负载污染画像) */
memory: 16Gi
---
/* VPA 推荐值 -> 资源画像数据源(定期导出分析) */
/* kubectl get vpa api-server-vpa -o jsonpath 提取 recommendation:
target: 推荐值(P90 历史用量)
lowerBound: 下界(低于此值有 OOM/限流风险)
upperBound: 上界(高于此值纯浪费) */
/* 画像漂移检测:本月推荐值 vs 上月推荐值 */
/* 变化 > 20% 触发审查:代码性能回归?流量构成变化?数据规模增长? */VPA(垂直扩缩容)与 HPA 解决不同维度的问题:HPA 调副本数(水平),VPA 调单副本的资源请求(垂直)。这份配置最有价值的设计是 updateMode: "Off"——VPA 只产出推荐值、不自动修改 Pod(自动垂直扩缩需要重建 Pod,对在线服务有中断风险,且推荐值异常时自动执行等于自动制造事故)。Off 模式下 VPA 的真正角色是「资源画像的自动采集器」:它持续观察每个容器的实际资源用量,用衰减直方图算法(近期数据权重高)计算 target(P90 推荐值)、lowerBound、upperBound 三个统计量——这恰好就是资源画像的运行时版本,比一年一次的压测画像新鲜得多。使用方式:每月导出 VPA 推荐值与 Deployment 的 requests 配置对比——requests 显著高于 upperBound 说明过度配置(浪费,可下调释放容量);requests 低于 lowerBound 说明配置不足(CPU 限流或 OOM 风险,必须上调)。这个对比流程自动化后就是「画像驱动的容量治理」:全集群扫描出过度配置和配置不足的服务清单,前者是成本优化的直接目标(Google 规模上,requests 平均下调 20% 释放的容量相当于数万台机器),后者是可靠性风险的提前拆除。画像漂移检测是 VPA 数据的第二个用途:推荐值月度环比变化超 20% 自动触发审查——上升可能是性能回归(新版本代码变慢)或数据规模增长(缓存变大),下降可能是优化生效或流量构成变化(重请求占比下降);无论哪种,都值得知道原因,因为容量计划依赖画像的稳定性假设。maxAllowed 的设置防止推荐值失控:VPA 的统计基于历史用量,异常事件(内存泄漏的 Pod、被攻击的流量)会污染直方图,上限约束保证即使推荐算法出错也不会把节点资源吃光。VPA 与 HPA 的共存注意事项:两者不能同时基于 CPU 指标工作(会互相打架——HPA 看到 CPU 高加副本,VPA 看到 CPU 高加配额),标准做法是 HPA 用自定义指标(活跃请求数)、VPA 用 Off 模式只做画像,或者用 Multidim Autoscaler 类方案统一决策。/* 示例 5:容量缓冲与水位管理(TypeScript 计算模型) */
interface CapacityParams {
safeUtilization: number; /* 安全水位线,如 0.8(拐点前) */
datacenters: number; /* 机房数 */
failurePolicy: "N+1" | "N+2";
forecastErrorP95: number; /* 预测误差的 95 分位,如 0.15 */
scaleUpLeadTimeHours: number; /* 扩容生效时间 */
growthRatePerHour: number; /* 峰值期小时增长率 */
}
function computeOperatingWatermark(p: CapacityParams): number {
/* 故障冗余:N+1 时,单机房故障后剩余机房水位 = 当前水位 * N/(N-1) */
const failoverFactor = p.failurePolicy === "N+1"
? p.datacenters / (p.datacenters - 1)
: p.datacenters / (p.datacenters - 2);
/* 约束 1:故障转移后不超过安全水位 */
const capByFailover = p.safeUtilization / failoverFactor;
/* 约束 2:预测误差缓冲——实际需求超预测 P95 时仍安全 */
const capByForecast = p.safeUtilization / (1 + p.forecastErrorP95);
/* 约束 3:扩容提前量缓冲——扩容生效前的增长空间 */
const capByLeadTime = 1 - (1 - p.safeUtilization)
+ p.growthRatePerHour * p.scaleUpLeadTimeHours;
/* 常态水位 = 三个约束的最小值(最紧的约束说了算) */
return Math.min(capByFailover, capByForecast, capByLeadTime * 0.9);
}
/* 例:3 机房 N+1、安全水位 0.8、预测误差 P95 15%、
扩容提前 2 小时、峰值期每小时增长 3%
故障约束: 0.8 / 1.5 = 0.533
预测约束: 0.8 / 1.15 = 0.696
提前量约束: 0.8 + 0.06 = 0.86(宽松)
=> 常态水位上限 0.533 * 0.9 ≈ 48%:故障冗余是最紧约束 */
/* 水位监控告警:绝对水位 + 消耗速率双维度 */
/* alert: watermark > 上限 * 0.9 持续 1h -> 启动扩容评估
alert: watermark 24h 内上升 > 10 个百分点 -> 异常增长排查
alert: watermark > 上限 -> page,立即扩容或限流 */这个模型把「常态水位应该控制在多少」从经验百分比变成可推导的计算,核心思想是三个独立约束取最小值。约束一(故障冗余):N+1 策略下,一个机房故障时其流量平摊到剩余机房,水位放大 N/(N-1) 倍——3 机房就是 1.5 倍,要保证放大后不超过安全水位 0.8,常态水位就不能超过 0.533。这解释了 Google「常态 60% 到 70%」水位的由来:它不是保守,是故障策略的数学结果;机房数越少,放大系数越狠(2 机房 N+1 意味着常态只能 40%)——多机房不仅是可用性投资,也是水位经济性投资。约束二(预测误差):需求预测的 P95 误差是 15%,意味着实际需求有 5% 概率超出预测 15%——常态水位要为此留空间,否则预测偏高的月份直接过载。约束三(扩容提前量):从决定扩容到容量生效需要 2 小时,峰值期每小时增长 3%,这 6% 的增长必须提前预留。三个约束中「最紧」的决定答案,例子里是故障冗余(48%)——这个诊断本身就有行动价值:想提高水位利用率,要么加机房(降低放大系数),要么改故障策略(接受 N+0.5:部分降级承接),要么提升安全水位(性能优化推迟拐点)。最后的 0.9 系数是模型误差的安全边际——约束模型本身也可能漏掉因素(维护窗口占用、碎片化损失),再打九折。告警设计的「双维度」同样重要:绝对水位告警(超过上限的 90% 启动评估)之外,消耗速率告警(24 小时上升超 10 个百分点)能更早发现异常——水位从 40% 到 50% 用了一个月是正常增长,用了三小时是异常流量(爬虫、攻击、客户端 bug),速率维度让响应提前数天。建议把这个模型做成组织的容量政策计算器:输入各服务的机房分布、故障策略、预测误差历史,输出各服务的常态水位红线——红线写入监控配置,突破即触发标准流程,容量管理从「凭感觉」变成「按公式」。/* 示例 6:成本优化查询集(PromQL + 分析脚本) */
/* 1. 过度配置检测:实际用量长期低于 requests 的 30% */
avg_over_time(
container_cpu_usage_seconds_total:rate5m{namespace="prod"}[7d]
)
/
kube_pod_container_resource_requests{resource="cpu",namespace="prod"}
< 0.3
/* 命中清单 = 下调 requests 的候选,按浪费核数排序 */
/* 2. 闲置资源检测:7 天几乎零流量的服务实例 */
sum by (service) (rate(http_requests_total[7d])) < 0.01
/* 零流量实例:确认无定时任务依赖后下线 */
/* 3. 单位业务成本趋势:每千次请求的 CPU 秒(画像漂移监控) */
sum(rate(container_cpu_usage_seconds_total{namespace="prod"}[1d]))
* 1000
/
(sum(rate(http_requests_total{namespace="prod"}[1d])) > 0)
/* 月度趋势上升 = 性能回归或流量构成变化,触发画像审查 */
/* 4. 实例类型性价比:spot 中断率监控(评估 spot 可用性) */
rate(cloud_spot_interruptions_total[30d])
/
avg_over_time(cloud_spot_instances_running[30d])
/* 中断率 > 5%/月 的工作负载应迁回按需实例 */
/* 5. 预留覆盖率:基线负载中被预留实例覆盖的比例 */
sum(cloud_reserved_instances_capacity)
/
quantile_over_time(0.1, sum(cluster_cpu_capacity_used)[30d:])
/* 目标:P10 基线负载的 80% 以上由预留覆盖(成本最优分层) */这组查询把成本优化从「财务部门的账单分析」变成「SRE 的日常工程实践」,五个查询对应五个优化杠杆。查询 1 的过度配置检测是最高性价比的起点:Kubernetes 集群中 requests 普遍虚高(开发者倾向「多要点保险」),用 7 天实际用量与 requests 的比值扫描,低于 30% 的就是下调候选——注意用 avg_over_time 的长窗口(7 天)而非瞬时值,避免把「周期性批处理负载」误判为闲置;下调的节奏要渐进(每次降 20%,观察一周无异常再继续),并优先从非核心服务开始积累流程信心。查询 2 抓「僵尸服务」:零流量实例的成本不只是机器本身,还有它占用的配额、监控、值班注意力——确认下线前检查定时任务和低频调用(7 天窗口可能漏掉月度任务,重要服务用 30 天窗口复核)。查询 3 是画像漂移的成本视角:每千请求 CPU 秒的月度趋势线是性能工程的成绩单——持续下降说明优化在生效,突然上升定位到具体服务就是性能回归的告警(比等容量出问题早得多)。查询 4 管理 spot 实例的风险收益比:spot 便宜 60% 到 90% 但随时被回收,中断率数据决定哪些负载适合 spot(无状态、可重跑、有快速迁移能力的),中断率上升(云厂商容量紧张期)时自动告警评估迁移。查询 5 优化采购结构:「基线加弹性」分层的量化验证——P10 负载(最稳定的基线部分)应该被预留实例覆盖 80% 以上(折扣最大化),P90 以上的波动部分用按需加 spot(弹性优先);覆盖率低说明预留买少了(多付按需溢价),覆盖率高过 P10 说明买多了(预留闲置也是浪费)。这组查询建议做成月度成本报表自动生成:每个查询的命中清单、环比变化、预估节省金额——成本优化的持续性依赖可见性,看得见的浪费才会被持续消灭。实验笔记
本实验的目标是完整走一遍容量规划循环:需求预测、资源画像、缓冲计算、扩缩容配置与成本审查,产出一份可用于真实决策的容量规划书。实验分五个部分,预计 5 到 6 小时,需要一个可压测的服务环境(实验环境的服务或测试环境的真实服务均可)和历史流量数据(没有真实数据时用合成的「趋势 + 周季节 + 噪音」序列)。第一部分:需求预测(约 1 小时)。收集或生成 90 天的日峰值 QPS 序列。用两种方法做 28 天预测并对比:方法 A 朴素基线——「过去 4 周同星期几的均值」;方法 B Holt-Winters(用示例 1 的代码或 statsmodels 直接调用)。评估方法:留出法——用前 62 天训练、后 28 天验证,计算两种方法的 MAPE 和峰值日误差。为预测加上置信区间(残差标准差法),输出 P50/P90/P95 三条预测曲线。再做一次突变检测练习:在验证集里人为注入一个「第 20 天起流量跳升 40%」的结构性变化,验证你的 drift 检测(偏差超 30% 告警)能在几天内发现它。检查清单:预测是否分位数形式?峰值日误差是否单独评估?季节性参数(周周期)是否正确设置?第二部分:资源画像与压测(约 1.5 小时)。对目标服务做梯度压测:从 10% 预估容量开始,每级增加 15%,每级持续 5 分钟达到稳态,记录每级的 QPS、P99 延迟、错误率、CPU 总消耗、内存。产出三个结果:性能曲线图(延迟 vs 负载,标出拐点和崩溃点);资源画像(用示例 2 的负载对比法回归出固定成本和边际成本,标注线性区上限);单实例安全容量(拐点 QPS 的 70%)。如果服务有多种请求类型(读/写/查询),分别压测得出分类型画像并计算当前流量构成下的加权画像。验证画像:用回归模型预测一个未压测负载点的 CPU 消耗,与实际压测值对比,误差应在 10% 内。第三部分:容量计算与缓冲设计(约 1 小时)。把预测和画像连起来:用 P95 预测曲线的峰值 QPS,代入画像换算需求核数,除以单机可用核(核数 × 0.7 安全利用率)得出机器数;再用示例 5 的三约束模型计算常态水位上限(输入你的机房数/可用区数、故障策略、预测误差 P95、扩容提前量);对比「按 P50 规划」与「按 P95 规划加 N+1 冗余」的机器数差异,把差额理解为「不确定性的价格」。产出一页容量规划书:需求预测(三条分位曲线)、画像数据(含测量日期)、机器数计算(逐步展示)、水位红线、扩容触发条件与提前量、下次复审时间。决策练习:如果你的计算结果是 28 台而现有 20 台,采购周期 6 周——写出你的行动计划(何时下单、过渡期的风险控制、如果预算只批 24 台怎么办:接受更低冗余并显式签署风险,还是推动性能优化降低画像值?)。第四部分:自动扩缩容配置与验证(约 1 小时)。在 Kubernetes 环境(minikube/kind 即可)为服务配置 HPA:主指标用 CPU 70%(有自定义指标条件时改用活跃请求数),minReplicas 按第二部分的安全容量计算(低谷 QPS ÷ 单副本安全 QPS,向上取整加 1),maxReplicas 按下游承载上限设定;配置 behavior 实现「扩容快缩容慢」(扩容稳定窗口 0、缩容 300 秒)。验证三个场景:场景 A 阶梯加压(负载每 2 分钟翻倍直到 4 倍),记录每次扩容的触发延迟、生效时间、期间 P99 的变化——扩容是否跑赢了负载增长?场景 B 负载回落后观察缩容行为,是否有震荡(反复扩缩)?场景 C 压测新副本的冷启动影响:扩容瞬间新 Pod 的延迟是否显著高于老 Pod(缓存冷),如果是,讨论慢启动方案。同时配置 VPA 为 Off 模式,运行一段时间后导出推荐值与 requests 对比,体验画像采集。第五部分:成本审查与复盘(约 45 分钟)。用示例 6 的查询(或简化版:导出各服务的实际用量与 requests 对比表)做一次成本审查:找出过度配置的服务(用量低于 requests 30%)、计算如果全部下调到 P90 用量加 20% 余量能释放多少资源、估算节省金额。复盘整个实验:预测的峰值日误差多大,对容量决策的影响是什么?画像的线性区假设在压测中成立吗?三约束模型里哪个约束最紧,意味着什么改进行动?最后回答思考题:你的服务如果明天流量突然翻三倍,从告警到容量就绪需要多久,中间用户经历什么?(这个问题串起了本章与第 6 章过载保护、第 9 章负载均衡——容量规划不是孤立学科,它的缺口由降级和均衡兜底。)
延伸阅读
- The Site Reliability Workbook 第 11 章 "Demand Forecasting and Capacity Planning"——本章原始出处,详细描述了 Google 的容量规划全流程:从时间序列预测、资源画像、到采购与部署的完整链条,包含 Borg 集群容量管理和 Google 年度规划周期的真实细节。原文对「预测必须带置信区间」和「画像持续更新」的强调是可直接落地的方法论。
- SRE 黑皮书第 17 章 "Testing for Reliability" 中的负载测试部分与第 26 章 "Data Integrity"——负载测试是容量数字的验证手段,黑皮书讨论了 Google 的生产压测实践(真实流量回放、影子压测);容量规划依赖的所有关键数字(单实例容量、集群拐点)都应经过这类测试验证,两章与本章构成「规划-验证」闭环。
- Forecasting: Principles and Practice(Rob Hyndman 与 George Athanasopoulos 著,O'Reilly 免费在线阅读,otexts.com/fpp3)——时间序列预测的权威教材,作者 Hyndman 是预测领域的泰斗(ets 和 forecast R 包的开发者)。书中对指数平滑、ARIMA、预测区间构造、预测精度评估的讲解深入浅出,第 3 章到第 8 章直接覆盖容量预测需要的全部方法,且免费在线阅读。
- Kubernetes 官方文档:Autoscaling Workloads——HPA、VPA、KEDA、Cluster Autoscaler 的官方指南,包括 autoscaling/v2 的 behavior 配置细节、VPA 的三种 updateMode、以及多自动扩缩组件共存的注意事项。配合本章示例 3、4 阅读,是落地自动扩缩容的第一手资料。
- Google Borg 论文:"Large-scale cluster management at Google with Borg"(EuroSys 2015)——理解 Google 容量利用率工程的源头:混部(在线服务与批处理共享机器)、优先级与抢占、资源画像与配额管理(alloc sets)。论文中「Borglet 级别的资源回收」(超卖空闲资源给批处理)是缓冲成本优化的经典设计,对理解大规模资源效率工程不可替代。
- AWS Well-Architected Framework:Performance Efficiency 与 Cost Optimization 两大支柱白皮书——云环境容量规划与成本优化的系统性指南,覆盖 rightsizing(资源画像校准)、弹性设计、预留实例策略、spot 使用模式。云上组织的容量实践清单,逐项对照自查通常能发现多个改进点。
- 《Queueing Theory 入门:The Tail at Scale 与 "What Happens When You Add a Server"》——排队论是容量规划「安全水位」概念的数学基础:利用率接近 100% 时延迟非线性飙升的机理、为什么 70% 是常见红线、加服务器对延迟分布的影响。Jeff Dean 的 The Tail at Scale(CACM 2013)从长尾延迟角度切入,与本章的水位管理互为表里。
- Netflix Tech Blog 的容量工程系列——包括 "Auto Scaling Production Services with Titus"、"Scryer: Predictive Auto Scaling" 等文章,展示了 Netflix 如何把机器学习预测与响应式扩缩结合(Scryer 系统提前数小时预测负载并预扩容)。与 Google 的画像驱动路线对比阅读,可以看到容量规划的两种工程风格:资源精确核算派与预测弹性派。