Day 27 Hard Cost Engineering Capacity Planning Autoscaling FinOps

成本与容量工程 — 在不破 SLO 的前提下把单位成本压下来Cost & Capacity Engineering: Planning, Attribution, Autoscaling, Efficiency

问题场景 + 需求约束

你接手一个月账单 $200 万、约 3000 个微服务跑在 Kubernetes 上的平台。CFO 要求 12 个月内单位成本(cost per request、cost per active user)降 30%,但任何服务的 p99 SLO 不许破。这不是「关几台机器省钱」,而是一个约束优化问题:在 SLO 约束下求资源效率最优。机会很大——业界在线集群的平均 CPU 利用率普遍只有 10–20%,Uber 公开把全局利用率从均值 20% 提到 31%,说明 headroom 浪费是常态。

高层架构(成本-容量闭环)

graph TD
    subgraph OBS["遥测 Telemetry"]
      M["运行指标
CPU · QPS · p99"] BILL["云账单
Billing / CUR"] end M --> PLAN["容量规划器
预测 + 排队论 headroom"] PLAN --> AS["Autoscaler
Reactive + Predictive"] AS --> SCHED["调度 / Bin-packer
Karpenter · Borg"] SCHED --> FLEET[("计算 Fleet
RI · Savings Plan · Spot")] FLEET --> M BILL --> ATTR["成本归因
Tag · 分摊"] ATTR --> FIN["FinOps 看板
cost / request"] FIN -.单位成本反馈.-> PLAN classDef obs fill:#0e2030,stroke:#5eead4,color:#e8eef5 classDef ctrl fill:#1a2530,stroke:#64c8ff,color:#e8eef5 classDef fleet fill:#1a1a30,stroke:#ffb450,color:#e8eef5 classDef fin fill:#2a1530,stroke:#ff7ab6,color:#e8eef5 class M,BILL obs class PLAN,AS,SCHED ctrl class FLEET fleet class ATTR,FIN fin

左半是「容量控制环」(指标→规划→扩缩→调度→fleet→回到指标),右半是「成本环」(账单→归因→看板),两环靠 cost/request 这个单位指标耦合。

关键技术点

1. 容量规划:利用率不是越高越省钱

原理:容量规划是在 SLO 约束下算「要多少资源」。三个输入:峰值负载(avg_qps × peak_factor)、单实例可承载量(压测得,不是看核数猜)、目标利用率。最反直觉的点:目标利用率不能设到 100%。排队论(M/M/c)告诉你,当利用率 ρ 趋近 1,排队等待 ∝ 1/(1-ρ) 呈非线性爆炸——利用率从 70% 升到 90%,等待时间翻数倍。所以存在一个 knee(拐点),多数在线服务把目标利用率定在 50–70%,留 headroom 吸收突发与单 AZ 故障(N+1/N+2 冗余)。

Trade-off:
# 容量规划: 在目标利用率下算所需实例数 (pseudo)
peak_qps    = avg_qps * peak_factor            # 日内波峰 (如 4x)
per_inst    = load_test_throughput             # 单实例可承载 QPS, 压测得
target_util = 0.65                             # 不是 1.0 —— knee 之前
need = ceil(peak_qps / (per_inst * target_util))
need += az_redundancy                          # N+1: 容忍单 AZ 挂掉
# 校验: 该利用率下 p99 是否仍在 SLO 内 —— 看压测曲线, 不要线性外推
现实案例:

2. 自动扩缩容:Reactive、Predictive、Scheduled

原理:自动扩缩容把「静态容量」变成「跟随负载」。三种范式:Reactive(看实时指标,如 K8s HPA target-tracking:指标偏离目标就调副本数)、Predictive(用历史预测未来负载、提前扩,如 Netflix Scryer)、Scheduled(已知规律,定时扩)。Reactive 的命门是 lag:指标采集 + 决策 + 实例启动 + 预热可能要几分钟,对秒杀级陡突发来不及。

Trade-off:
# HPA target-tracking 核心公式
desired = ceil(current_replicas * (current_metric / target_metric))
# 例: 10 副本, 当前 CPU 90%, 目标 60% -> ceil(10 * 1.5) = 15 副本
# 防震荡: scale-in 看过去 5 min 最大值 (stabilization window) + cooldown
# 关键不对称: scale-out 要快, scale-in 要慢 —— 缩太快遇下一波突发就破 SLO
现实案例:

3. 成本归因:没有 unit economics 就没有优化

原理:3000 服务、500 团队,一张 $200 万总账单根本没法优化——必须把成本归因到团队/产品/请求。FinOps 的核心是 showback/chargeback:用资源 tag(team、service、env)把账单切片,再把共享成本(公用 LB、控制面、跨服务 DB、Spot 折扣)按某个 key 分摊下去。终点是 unit cost:cost per request、cost per active user——这才是能跨时间比较、能进决策的指标。

Trade-off(共享成本怎么分摊):
# unit economics: 把账单变成可决策指标
team_cost = direct_cost[team] + shared_cost * (team_usage / total_usage)
unit_cost = team_cost / team_requests        # $ / 1k req —— 可跨季度比
# 看趋势 > 看绝对值: cost/req 环比上涨 = 有服务在变低效, 该告警
现实案例:

4. 资源效率:rightsizing、bin-packing、采购三层

原理:利用率从 15% 提到 45% 就是省 3 倍钱。四个杠杆:① Rightsizing——requests/limits 贴合真实用量(VPA、Autopilot 自动调);② Bin-packing——调度器把 pod 紧密塞进节点、减少碎片;③ Consolidation——周期性重新打包、退掉空节点;④ 采购组合——基线用 Reserved/Savings Plan(省 ~40–60% 但锁 1–3 年)、弹性峰用 On-demand、容错批处理用 Spot(省 ~70–90% 但随时被抢占)。

采购类型省多少代价 / 适用
Reserved / Savings Plan~40–60%锁定 1–3 年,架构变了会错配;放稳定基线
On-demand0(基准价)最贵但不被抢;放弹性峰值兜底
Spot~70–90%随时被回收(~2 min 通知);只放可中断/可重试负载
# 节点采购决策: 基线买承诺折扣, 弹性用 Spot 兜 On-demand
if workload.interruptible and spot_available:
    launch(SPOT)            # 省 70-90%, 收到抢占通知 -> 优雅迁移
elif load <= committed_baseline:
    use(RESERVED)           # 基线锁价, 省 40-60%
else:
    launch(ON_DEMAND)       # 峰值兜底, 最贵但不被抢
现实案例:

扩展与优化(增长后怎么演进)

常见陷阱 + 面试问题

陷阱 1:把利用率往 100% 推。 忽略排队论 knee,p99 在 ~80% 后非线性恶化,省下的机器钱会被 SLO 违约赔回去。
陷阱 2:scale-in 太激进。 缩完立刻来突发,反复 flapping,比不缩还糟;scale-out 快、scale-in 慢是铁律。
陷阱 3:只看总成本不看 unit cost。 业务涨 2 倍、成本涨 2 倍是健康的;要盯 cost/req 趋势而非绝对值。
陷阱 4:Spot 当 On-demand 用。 把有状态/不可中断服务放 Spot,大面积回收时丢数据/塌容量。
陷阱 5:tag 不全 / 预留买太满。 20–30% 成本进 unallocated 桶则归因失效;RI 锁 3 年后架构一变,错配可能比 On-demand 还贵。

面试可能追问:

  1. 服务平均 CPU 15%,老板要砍一半机器,你怎么判断能砍多少?(headroom、峰值因子、排队论 knee、N+1 冗余)
  2. Reactive 和 predictive autoscaling 各自什么场景?怎么组合?冷启动 lag 怎么办?
  3. 一张 $200 万账单怎么归因到 500 团队?共享成本(LB、控制面、Spot 折扣)怎么分摊才公平?
  4. 什么负载适合 Spot?被抢占怎么优雅处理?怎么控制抢占风险?
  5. cost per request 突然涨 20%,怎么定位是哪个服务、什么原因?

深入资源

深入思考(点击展开答案)

1. 把利用率从 70% 推到 90% 省了机器,为什么 p99 反而可能让你赔更多钱?

关键在排队论的 1/(1-ρ) 分母。利用率 70% 时排队因子 ∝ 1/0.3 ≈ 3.3;90% 时 ∝ 1/0.1 = 10——等待时间约翻 3 倍,而且越靠近 1 越陡。省下的机器是线性的(少买 ~22% 节点),但 p99 恶化是非线性的,很容易击穿 SLO。账要这么算:省下的实例成本 vs(SLO 违约赔付 + 超时触发的客户端重试放大 + 重试又进一步抬高 ρ 形成正反馈)。headroom 的价值正是「吸收突发、给排队留缓冲」,把它当浪费砍掉,是拿尾延迟的稳定性换账面数字。结论:利用率目标该由 SLO 下的延迟曲线反推,而不是拍一个「越高越好」。

2. predictive autoscaling 低估了突发,会怎样?怎么让它「错也安全」?

预测式一旦欠配,扩容来不及就是 lag 期内 SLO 直接破——比纯 reactive 更糟,因为你「以为不用扩」而压低了基线。让它 fail-safe 的设计:① 不对称惩罚——over-predict 只多花点钱,under-predict 会违约,所以预测要带安全余量、宁可略微高估。② 分层兜底——predictive 只用来设容量下界(提前把基线抬上去),reactive 仍挂在上面负责抓住预测没料到的尖峰。③ 置信区间——预测输出带不确定度,波动大的时段自动加 headroom。④ 回退——预测信号异常(数据缺失、模型漂移)时降级为纯 reactive,绝不让一个坏预测把容量压到地板。本质是把「预测」当优化项、把「reactive + headroom」当安全网。

3. 利用率极高、Spot 比例极高,看着很省。这套「极致效率」什么时候反咬一口?(呼应 Day 23 可靠性)

效率与韧性是对立的。把 headroom 榨干、Spot 拉满,等于系统性地移除了所有缓冲① 故障吸收能力归零——单 AZ 挂掉,剩余节点本就满载,流量一转移立刻雪崩(没有 N+1 接得住)。② Spot 容量是共享池,AWS 回收往往按实例类型/AZ 批量发生,你和无数人抢同一池子,大面积回收时容量瞬间塌方。③ 自动扩缩的 lag 在高利用率下更致命——本就没冗余,扩容那几分钟无人兜底。所以「极致效率」适合可中断的批处理,绝不适合承载 SLO 的在线主路径。正确姿势是分层:核心在线服务留 headroom + On-demand/RI 保底,弹性与离线负载吃 Spot 与高利用率。省钱要省在能承受波动的地方。

4. cost per request 是好指标,但它什么时候会骗你?

它是个比值,分子分母都能被玩坏。① 分母稀释——往里灌大量廉价请求(健康检查、轮询、重试),cost/req 账面下降,实际总成本没动甚至上升。② 请求不同质——一次搜索和一次静态页成本差百倍,平均值掩盖了「贵请求」,该看 P50/P99 请求成本分布而非单一均值。③ 固定成本在低流量时主导——控制面、最小副本数是固定的,流量低谷时 cost/req 飙高,但那不代表低效。④ 跨服务成本转移——A 把计算推给 B,A 的 cost/req 好看了,全局没变。⑤ 该看边际成本——决策「值不值得多接这波流量」要的是边际成本,不是摊薄后的平均。一句话:cost/req 适合看趋势和告警,但做决策要拆到请求类型、区分固定/边际、警惕分母游戏。

5. 一个团队为省自己的账单,把任务全塞到 Spot 和夜间批处理。本地最优,对整个平台是好是坏?

典型的公地悲剧 + 二阶效应。单看这个团队:用 Spot、错峰,账单确实降了,showback 数字漂亮。但放到平台尺度:① Spot 是共享容量池,大家都被激励去抢,夜间窗口很快也变成「峰」,抢占率上升、可用容量下降,最后谁都没省到预期。② 夜间批处理扎堆会把原本的低谷填平,削峰红利消失,还可能挤占夜间的备份/维护窗口。③ 激励设计的锅——如果分摊 key 让 Spot 折扣只归使用者、却不反映「抢占给别人造成的外部性」,就会鼓励过度集中。解法是把全局视角放进归因与调度:错峰给差异化价格信号(越拥挤的时段越贵)、平台层做跨团队的 Spot 多样化与 workload 时间打散,让局部最优与全局最优对齐。这正是成本归因里「分摊 key 怎么选」会塑造行为的体现。