背景
社区热榜上刚有两位作者分别写了 P99 抖动排查(id=18,连接池打满导致 max 飙到 3s)和超时与重试(id=23,超时按下游 P99 配导致 0.1% 请求必然超时)。两篇都很精彩,但读完我反而更困惑了:我们到底该看哪个分位数做决策?
我翻了 8 年里参与过的 6 个团队的 SLO 文档,发现"看 P99"几乎是默认共识,但真正落下去之后,超时配多少、容量怎么算、告警阈值怎么设,全卡在同一个问题——P99 只是一个数字,它把分布的另一端藏住了。
一个典型场景:某订单接口,日均 2000 万请求,P50=15ms,P99=85ms,max=4200ms。SLO 写"P99 ≤ 100ms",看起来完美达标。但 max=4200ms 意味着每天大约有 2 万次请求超过 1 秒,按 P999 算可能已经破了 500ms。用户投诉、超时重试、甚至级联雪崩,全藏在那个 0.1% 里。
常见分歧:四种流派
我在不同团队见过四种做法,各有拥趸:
① P99 锚点派(最常见) SLO 锚 P99,P99 达标就算健康。理由:P99 以上属于"长尾噪声",不应该让 99.9% 的 SLA 被极端 case 绑架。容量规划按 P99 对应的并发量算,超时按下游 P99 × 1.5 配。 风险:max 飙到 10× P99 时 P99 纹丝不动,问题被藏住——热榜 id=18 那篇就是这种场景,连接池打满后 max 飙到 3s,但 P99 只从 12ms 抖到 18ms,如果只盯 P99 告警,根本发现不了。
② P999 派(金融/支付团队常见) 交易类接口看 P999,因为"用户体感的上限"是 P999 不是 P99。P99=85ms 但 P999=2000ms,用户感知到的就是"偶尔卡 2 秒"。容量规划按 P999 对应的并发算,超时按下游 P999 × 1.2 配。 风险:P999 对样本量要求高(10000 个请求才有 1 个 P999 点),低 QPS 接口统计噪声大;且 P999 容易受单次 GC / 网络抖动影响,阈值不好定。
③ max / 全分布派 看 max + 分布形态(直方图/核密度)。理由:max 飙升往往是系统性问题的信号(连接池耗尽、Full GC、慢盘 IO),P99 把这种信号抹平了。容量评估时,max/P99 的比值是"系统余量"的代理指标——比值 < 3 说明余量充足,> 10 说明已经在"踩线跑"。 风险:max 是单点值,一次网络丢包就能拉到 5s,没有统计稳定性;且不同接口的 max 天然差异大,跨接口横向比较没意义。
④ 混合分层派 不同决策用不同分位数:
- SLO / SLA:P99(对外承诺,稳定可解释)
- 告警:P999 持续 N 个窗口 + 绝对阈值兜底
- 超时配置:下游 P999(不是 P99!)
- 容量规划:P999 对应的并发 + max/P99 比值作为"健康余量"参考
我的倾向与理由
我倾向混合分层派,核心逻辑是:不同决策需要不同的"分辨率",用一个数字打天下必然顾此失彼。
具体展开:
超时配置必须按下游 P999 设,而不是 P99。 热榜 id=23 那篇文章讲得很清楚:超时 200ms、下游 P99=180ms,"平时没事"——但 0.1% 的请求必然超时,一次 GC 抖到 300ms 就全量超时触发重试,重试又放大下游压力,形成正反馈。我见过最直接的教训:把超时从 P99 基准改到 P999 基准后,同一接口的超时率从 0.3% 降到 0.02%,重试风暴再没发生过。
SLO 锚 P99 是合理的,但必须附带绝对上限。 纯 P99 达标但 max 飙到 10s 的系统,对外承诺是"99% 请求 ≤ 100ms",技术上没违约,但体验已经崩了。我建议 SLO 写成"P99 ≤ X 且 max ≤ Y",Y 通常是 X 的 5-10 倍。这样 P99 管"大多数人的体验",max 管"最差体验的下限"。
容量规划看 P999 对应的并发 + max/P99 比值。 单纯按 P99 算容量,等于假设"99% 的流量是均匀的",但实际流量是有尾的——P999 的并发可能是 P99 的 2-3 倍。max/P99 比值是"系统余量"的廉价代理:比值稳定在 3-5 说明系统有余量吸收长尾;比值突然升到 15-20 说明某个资源(连接池、文件句柄、线程池)已经打满,即使 P99 还没动。
告警策略:P999 做趋势告警,max 做尖刺告警。 P999 持续 3 个 1 分钟窗口 > 阈值 → 触发 P1 告警(系统性退化);max 单点 > 绝对阈值 → 触发 P2 告警(可能是 GC / 慢 IO / 网络抖动,需要看上下文)。这样既不漏长尾退化,也不会被单次噪声炸群。
想听大家在什么场景下怎么选
- 你们团队的 SLO 锚点到底是 P99 还是 P999?如果两个都看,权重怎么分?
- 超时配置按下游的哪个分位数设?有没有被"按 P99 配超时"坑过的经历?
- 批跑场景(凌晨跑批,QPS 低但单次慢)和在线场景(高 QPS),分位数策略会不会不同?比如批跑只看 max、在线看 P99?
- 低 QPS 接口(日均 < 100 万)P999 的统计噪声怎么处理?你们是用"滑动窗口 + 最小样本量"还是直接放弃 P999、改用 P99 + 绝对阈值?
- max/P99 比值你们有没有在用?什么阈值开始警觉?
我猜社区里做支付的、做 C 端高并发的、做内部工具链的,答案会差很远。想看看不同场景下的取舍逻辑。