加机器、加核、加人,到底能快多少?Amdahl 定律给出上限,Karp–Flatt 指标帮你从压测数据里诊断瓶颈,USL 解释为什么扩容到某个点后性能反而下降。再配上 Little 定律和排队论,就能把容量规划从"拍脑袋"变成可以算的事。
文中每条定律都配了一个可交互的图或计算器,数值都可以改,表格会跟着重新计算。
一、Amdahl 定律:总时间等于各部分时间之和
加速只能作用在其中一部分上,所以整体加速受未加速部分限制。把单核总耗时记为 1,其中可并行部分占 ,串行部分占 :
- 串行部分不变:
- 并行部分分给 个核:
当 ,:串行占 10% 时,加速上限是 10×。
推广到多个部分
各部分可以有不同的加速倍数,整体加速为:
是第 部分的耗时占比, 是它的加速倍数。以一次请求为例:
| 阶段 | 耗时占比 | 优化后加速 | 优化后耗时 |
|---|---|---|---|
| 解析请求 | 20% | 不变 | 0.20 |
| 查询数据库 | 50% | 加缓存,5× | 0.10 |
| 渲染结果 | 30% | 并行化,3× | 0.10 |
| 合计 | 100% | 0.40 |
整体加速 = 1 / 0.40 = 2.5×。这时如果把"解析请求"优化到无限快,总耗时也只从 0.40 降到 0.20。下面的计算器里,改各段的占比和加速倍数(拉到最右是无限快),看整体加速和最后一列的上限怎么变:
该优化哪一段,可以直接算出来:先看每一段占多少时间,再看能加速多少。最后一列就是"这一段做到极致,整体最多能快多少",它比优化前的直觉更可靠。
二、Karp–Flatt 指标:从实测数据反推串行比例
实际项目里 往往不知道。先测出加速比 ,再反推出"实测串行比例" ,然后看 随 怎么变化,就能判断瓶颈属于哪一类。
| N | 情形 A:实测 S | A 的 e | 情形 B:实测 S | B 的 e |
|---|---|---|---|---|
| 8 | 5.0× | 0.086 | 5.0× | 0.086 |
| 16 | 7.0× | 0.086 | 6.0× | 0.111 |
| 32 | 8.8× | 0.085 | 5.5× | 0.155 |
- e 保持不变(情形 A):瓶颈是固定的串行代码,符合 Amdahl 模型。应该去找并缩短那段串行逻辑。
- e 随 N 增大(情形 B):瓶颈是协调开销,比如锁竞争、缓存一致性、跨节点通信。继续加核反而有害,需要用下一节的 USL 来解释。
把你自己的压测结果填进下面的表,它会算出每个 N 的 e 并给出判断:
情形 B 也说明了一件事: 不是常量。同步开销会让有效的 随 下降,而数据量变大时,并行部分的占比通常又会上升。所以用一次单机测得的 去推算 32 核的表现往往不准,要按 实测。
三、USL:为什么加机器后性能反而下降
Amdahl 的曲线只会趋平,Neil Gunther 提出的通用可扩展性定律(USL)在此基础上多加了一项。只要一致性开销 ,吞吐曲线就会出现峰值:
- α(竞争):排队等待共享资源,比如全局锁或单主库。它就是 Amdahl 中的串行部分。
- β(一致性):节点之间互相同步状态的开销,按 增长。
峰值所在的节点数:
以 α = 0.05、β = 0.001 为例,峰值大约在 31 个节点。拖动下面的滑块,看 α 和 β 分别怎样改变曲线:
β 取 0 时,USL 就退化为 Amdahl。
用压测数据拟合 α 和 β
实际用法是在 1、4、8、16、32 个副本下分别压测吞吐,用这几个点拟合出 α 和 β,就能在 HPA 扩容之前预测扩容会在哪里失效。把公式变形,USL 就变成一个关于 α、β 的线性方程,普通最小二乘就能解:
其中 ,即 N 个副本的吞吐除以单副本吞吐。把你的压测结果填进下表,拟合会实时完成:
单副本吞吐 X(1) 是拟合的基准。如果没法只跑一个副本,可以把 X(1) 也当成未知数,用非线性拟合一起求出来。
四、落到微服务:α 和 β 从哪里来
HPA 横向扩容只能加速可并行的部分。在微服务和 GKE 里,USL 的两个参数都有具体的来源,看清它们,就知道扩容会在哪里提前触顶。
| 参数 | 含义 | 微服务里的典型来源 | 加副本有没有用 |
|---|---|---|---|
| α(竞争) | 大家排队用同一个东西 | 单主库写入、分布式锁、热点 key;单实例 cron 或控制器;共享限流器、连接池上限;所有流量都过的 Istio ingress、单实例聚合的 OTel Collector | 没用,要拆掉这个串行点 |
| β(一致性) | 节点之间互相同步 | 缓存失效广播、gossip 协议、一致性哈希环重平衡、大网格里每个 Envoy 都要接收的 xDS 全量配置推送 | 有害,开销随实例数增长,有的按平方增长 |
扇出请求:一个随 N 变长的串行段
还有一种不那么明显的串行段。一个请求并行调用 N 个下游,总延迟取决于最慢的那一个。假设每个下游的 P99 是 100ms,扇出到 100 个下游时,至少有一个超过 100ms 的概率是 1 − 0.99¹⁰⁰ ≈ 63%。这个"等最慢的那个"的时间随 N 变长,所以实际效果比 Amdahl 预测的还要差。
常见的缓解办法是对冲请求(hedged request:等待超过某个分位数就向另一个副本再发一次),只有两次都慢才算慢。拖动下面的滑块,看扇出宽度和单个下游的慢请求比例怎样影响整体:
这里假设各下游独立、对冲请求发到另一个副本后也独立。真实环境里慢往往是相关的(同一台宿主机、同一次 GC),效果会打折扣,但趋势一样:扇出越宽,尾延迟越难控制。其他办法还有给每个下游设超时并允许返回部分结果,或者直接减少扇出的宽度。
五、Little 定律:系统里同时有多少请求
系统中的平均请求数,等于到达率乘以平均停留时间。这个关系对任何稳定系统都成立,不需要假设到达或服务的分布。
是系统中的平均请求数(在途请求、队列长度), 是到达率(吞吐), 是平均停留时间(延迟)。已知其中两个,就能求出第三个:
| 场景 | 已知 | 求出 |
|---|---|---|
| 服务在途请求 | 1000 RPS,平均延迟 200ms | L = 1000 × 0.2 = 200 个并发 |
| 数据库连接池 | 500 QPS,平均查询 20ms | L = 500 × 0.02 = 10 个连接(再留余量应对尖峰) |
| Kafka 消费积压 | 积压 60,000 条,消费速率 2,000 条/s | W = 60,000 / 2,000 = 30s 端到端延迟 |
| OTel Collector 队列 | 50k span/s,导出延迟 400ms | L = 20k span,队列至少要能容纳这么多,否则会丢 |
| 全局锁 | 并发度只有 1,持锁 2ms | λ = 1 / 0.002 = 500 次/s 的吞吐上限 |
点上面任意一个场景,或者自己填数:
与 Amdahl 的联系:表里最后一行就是 Amdahl 的串行瓶颈在吞吐维度上的表现。一把全局锁的并发度 L 只有 1,持锁 2ms 时,整个系统的吞吐上限就是 500 次/s,加多少实例都无法突破。
常见误用:延迟升高后,并发数 L 会跟着上涨。所以只调大线程池、不降低 W,结果只是更多请求排在队里。
六、利用率与排队延迟
利用率从 50% 升到 90%,响应时间不是增加 80%,而是变成原来的 5 倍。下面三条公式从不同角度描述这个现象。
利用率定律:资源的利用率 U 等于吞吐 X 乘以单次服务时间 S。例如单次请求占用 10ms CPU,每秒 80 个请求,利用率就是 80%。
| 利用率 ρ | 响应时间 R(S = 10ms) | 是 S 的几倍 | 系统内平均请求数 |
|---|---|---|---|
| 50% | 20ms | 2× | 1 |
| 70% | 33ms | 3.3× | 2.3 |
| 90% | 100ms | 10× | 9 |
| 95% | 200ms | 20× | 19 |
拖动利用率,或者直接在图上点选,看响应时间怎样随负载变化:
Kingman 公式(适用于 G/G/1,即到达和服务时间可以是任意分布):排队等待时间是"利用率因子"乘以"波动因子"。
和 分别是到达间隔和服务时间的变异系数(标准差除以均值)。M/M/1 对应 ;流量突发、请求耗时差异大,都会让它们大于 1,成倍拉长排队时间。下面的图把你的波动和 M/M/1 放在一起比:
工程含义:HPA 的目标 CPU 利用率通常设在 60–70%,而不是 90%。剩下的余量是在为尾延迟买单,并不是浪费。另一个有效的办法是降低波动:限流削峰、把慢请求分到单独的队列。
七、Gustafson 定律:问题规模随算力一起变大
常有人说"Amdahl 证明了并行没用"。其实它说明的只是:问题规模固定时,加速上限取决于串行部分。GPU 训练、MapReduce 这类场景,问题规模会随算力一起扩大,适用的是 Gustafson 定律。
如果核数增加时问题规模也同比例放大,而串行部分基本不变,那么加速比可以接近线性。以 p = 0.9、N = 100 为例,Gustafson 的结果是 90.1×,而 Amdahl 只有 9.2×。
| N | Amdahl(规模固定) | Gustafson(规模放大) |
|---|---|---|
| 10 | 5.3× | 9.1× |
| 100 | 9.2× | 90.1× |
| 1000 | 9.9× | 900.1× |
改变并行占比 p,看两条曲线和下面的表格怎么变(两个坐标轴都是对数刻度):
注意两个定律里的 p 含义不同:Amdahl 的 p 是在单核上测得的并行占比,Gustafson 的 p 是在 N 核上测得的并行占比。两个定律本身并不矛盾,只是回答的问题不同:
- Amdahl 问的是"同样的活能干多快",适用于在线请求的延迟;
- Gustafson 问的是"同样的时间能干多大的活",适用于离线批处理、模型训练、大数据作业。
在 HPC 领域,这两种测法分别叫强扩展(strong scaling,问题规模固定)和弱扩展(weak scaling,每个核分到的工作量固定)。看别人发布的扩展性数据时,先确认是哪一种,否则结论可能差一个数量级。
八、Brooks 定律:团队里的 β 项
向一个已经延期的软件项目加人,只会让它更晚完成。
—— Fred Brooks,《人月神话》(1975)
这句话可以看作 USL 在团队协作上的版本。
- α 对应不可拆分的任务:有些工作必须按顺序做,比如架构决策、关键路径上的模块。这部分加人也快不了。
- β 对应沟通开销:N 个人之间的沟通通道数是 N(N − 1)/2。
- 新人上手成本:新成员前几周还会占用老成员的时间,短期内团队的有效产出反而下降。
| 团队人数 | 沟通通道(不拆分) | 拆成 4 个小组后 |
|---|---|---|
| 5 | 10 | 7 |
| 10 | 45 | 14 |
| 20 | 190 | 46 |
拆成小组后,通道数 = 各组内部的通道 + 各组负责人之间的通道。下面用 USL 的形式估算团队的有效产出,把每条沟通通道的开销记作 β:
这个模型很粗糙,β 的取值也只是示意,但结论和优化系统时一样:减少 β,也就是按模块拆分团队、定义清晰的接口;缩短 α,也就是提前做好架构决策,让关键路径上的工作尽早解耦。
总结
做容量规划时,可以按这个顺序依次使用:
- 上限:用 Amdahl 估算串行部分决定的加速天花板。
- 诊断:在几个 N 下压测,用 Karp–Flatt 判断瓶颈是串行还是协调开销。
- 扩容拐点:用同一组数据拟合 USL,算出副本数的峰值 N*,HPA 的
maxReplicas设在它之下。 - 排队余量:用 Little 定律算池和队列的容量,用 M/M/1 和 Kingman 决定目标利用率留多少余量。
| 定律 | 回答的问题 | 公式 | 典型用途 |
|---|---|---|---|
| Amdahl | 规模固定时最多能快多少 | S = 1 / ((1 − p) + p/N) | 评估优化或并行化的收益上限 |
| Karp–Flatt | 瓶颈属于串行还是协调开销 | e = (1/S − 1/N) / (1 − 1/N) | 用压测结果诊断扩展性 |
| USL | 扩容到哪里开始适得其反 | C = N / (1 + α(N−1) + βN(N−1)) | 预测副本数的峰值 N* |
| Little | 系统里同时有多少请求 | L = λ·W | 估算连接池、线程池、队列容量 |
| 利用率 / M/M/1 | 负载多高时延迟开始失控 | U = X·S,R = S/(1 − ρ) | 设定 HPA 目标利用率、预留余量 |
| Kingman | 流量波动让排队变差多少 | W_q ≈ ρ/(1−ρ) · (cₐ² + cₛ²)/2 · S | 判断是该削峰还是该扩容 |
| Gustafson | 规模随算力扩大时能干多大的活 | S = (1 − p) + p·N | 批处理、训练任务的扩展预期 |
| Brooks | 加人能不能让项目更快 | 沟通通道 N(N − 1)/2 | 团队规模与拆分决策 |
参考资料
- Gene Amdahl,Validity of the Single Processor Approach to Achieving Large Scale Computing Capabilities,AFIPS Spring Joint Computer Conference,1967
- Alan Karp、Horace Flatt,Measuring Parallel Processor Performance,Communications of the ACM,1990
- Neil Gunther,Guerrilla Capacity Planning,Springer,2007
- Jeffrey Dean、Luiz André Barroso,The Tail at Scale,Communications of the ACM,2013
- John Little,A Proof for the Queuing Formula: L = λW,Operations Research,1961
- J. F. C. Kingman,The Single Server Queue in Heavy Traffic,Mathematical Proceedings of the Cambridge Philosophical Society,1961
- John Gustafson,Reevaluating Amdahl's Law,Communications of the ACM,1988
- Fred Brooks,The Mythical Man-Month(《人月神话》),1975