← 中文资源

简体中文版本

API 延迟 SLO 调优工作流

按流量现实定分位数延迟 SLO,把 p99 分解为组件跨度,对主导路径调优并以测量验证。

阅读英文原文

目标

平均延迟描述快乐路径,SLO 却住在 p99——那里由完全不同的原因主导:缓存未命中、慢分片、重试放大。把尾部分解成组件跨度,找出拥有爆表的那一个,只修它就能动 SLO。二峰分布的跨度(命中与未命中)几乎总是违规所在地。

步骤要点

  1. 从分布现实定 SLO:按当前分布与用户期望给每类端点定分位数目标,选积极但不虚构的 p95 与 p99。
  2. 把尾部分解为跨度:对 p99 违规的端点把请求拆成跨度(校验、下游调用、序列化),按尾部贡献排名。
  3. 调优主导组件:修尾部贡献最高的——并行独立调用、可重复处加缓存、削减载荷或收紧下游超时。
  4. 在尾部而非均值验证:部署后对端点对比 p99 与 p99.9,观察至少一个含峰值的完整流量周期。
  5. 用告警与预算守住收益:给调优过的端点接 SLO 燃烧告警,记录达成的基线供下一轮使用。

排错提示

命中率 95% 听起来很好却独占 p99,未命中的 5% 各付全额源站成本,看二峰分布的跨度;单项调用 180ms 看着能忍,二十个条目 N+1 放大后 p99 继承二十次抽样最差的那个;只报均值改善是自欺,验证指标必须是对齐 SLO 的那个分位数。

适用边界

跨度分解依赖埋点的完整性,未打点的黑盒调用是归因盲区;尾部行为受流量结构影响,峰值周期内的验证不可省略。

代码示例

endpoint: GET /api/feed   SLO: p99 <= 500ms
field: p99 = 2.4s (violating), p50 = 90ms

span decomposition (p99 contributions):
  auth.token       8ms    (flat)
  feed.query       310ms  (cache-hit: 4ms)
                        cache-miss p99: 900ms <- DOMINANT
  media.presign    180ms  (per-item, N+1)
  serialize        22ms

fixes (ranked by tail contribution):
  1 feed.query: warm + stale-while-revalidate
    (miss rate 11% -> 0.4%)   p99 span: 900 -> 60ms
  2 media.presign: batch + 5min cache  180 -> 21ms

after (7d incl. peak): p99 = 380ms   SLO: MET