【背景】 做了 5 年网络工程,跨机房 HTTP/gRPC 调用链,复盘过不少"数字打架"的事故。最典型的一次:
支付接口 SLO 定的是 99.95%,季度复盘时 SRE 报"达标"——因为 429(限流拒绝)和 503(下游熔断)在他们口径里不算"服务错误",只有 5xx + 超时才算。但业务方拉了用户侧日志:有 0.08% 的请求被 429 挡住了,用户没完成支付。业务说"不达标",SRE 说"我的 SLO 定义里 429 是正确拒绝"。
吵了三个会,最后靠 VP 拍板。
我越来越觉得,SLO 里"什么算一次失败"这个定义,比 SLO 本身定多少更影响团队行为。口径不对齐,99.95% 和 99.9% 根本不是同一个数字。
【常见分歧 / 几种做法】
我观察下来,团队里至少有三派:
派 1:服务端正确性派(SRE 居多) "我返回了 200 / 429 / 503,说明我按设计正常工作了。429 是限流策略生效,503 是熔断保护,都不是 bug。SLO 只统计 5xx + 超时(含重试后仍失败)。"
- 好处:口径干净,和代码行为一一对应,告警规则好写。
- 问题:用户视角完全丢失。429 对用户来说就是"我没买到",和 500 没有体验差异。
派 2:用户结果派(产品 / 业务居多) "不管服务端返回什么,用户没拿到预期结果就是失败。429 算失败,降级返回空数据算失败,超时后重试成功但延迟 2 秒也算失败(SLO 里应该同时约束成功率和延迟)。"
- 好处:和业务收入直接挂钩,SLO 有"牙齿"。
- 问题:口径模糊——"预期结果"谁来定义?降级返回了缓存数据算成功吗?部分成功(聚合接口 7 个下游 5 成 2 败)算成功还是失败?
派 3:分层口径派(我目前倾向的) 拆成两个数字,各管各的:
- 技术 SLO(SRE / 值班用):5xx + 超时(含重试后仍失败)= 失败。429 / 503 单独出指标,进"容量 / 限流健康度"看板。
- 业务 SLO(对齐 SLA / 合同):用户未完成预期操作 = 失败。包括 429、降级、超时重试成功但延迟超阈值。
- 两层都有明确的 dashboard、告警和复盘触发条件。
【我的倾向与理由】
从网络工程的角度,我倾向 派 3(分层),核心理由有三:
-
驱动行为不同。 技术 SLO 的失败会触发 on-call、复盘、热修;业务 SLO 的失败会触发容量规划、限流阈值调整、产品降级策略评审。如果混在一个数字里,团队会"挑对自己有利的口径"——SRE 挑 429 不算失败,业务挑超时重试算成功。分层后各管各的,少吵架。
-
可观测性落地不一样。 技术 SLO 用服务端指标(Prometheus / eBPF)就能算,精确到 ms;业务 SLO 需要端侧埋点或网关日志,采样和归因复杂度高一到两个量级。混在一起会导致"为了算一个数字,把观测系统搞得很重",ROI 极低。
-
重试成功到底记几次,是个陷阱。 我见过团队把"超时后重试成功"在 P99 里记 1 次(因为最终成功了),结果 P99 看起来 200ms,但用户实际等了 2 秒。也见过团队记 2 次(一次失败 + 一次成功),P99 直接飙到 2s,但"错误率"虚高。这个不是"谁对谁错"的问题,是口径必须写进 SLO 定义文档里,而不是靠口头对齐。
具体做法(我目前在用的):
- SLO 定义文档里强制写三行:① 失败的判定条件(精确到 HTTP 状态码 / gRPC status / 超时阈值);② 重试策略(几次、间隔、是否计入失败);③ 分母定义(是"所有请求"还是"进入处理链路的请求",429 进不进分母)。
- 每季度用真实事故回测一次口径:这次事故在技术 SLO 里算几次失败?在业务 SLO 里算几次?如果答案不一致,说明口径需要调整。
【想听大家怎么选】
抛几个具体问题,想看看不同规模、不同技术栈的团队怎么定:
- 429 / 限流拒绝:在你们的 SLO 里算失败还是成功?进分母吗?
- 超时后重试成功:P99 统计里这条请求记 1 次(成功,延迟 = 重试总耗时)还是 2 次(一次失败 + 一次成功)?错误率里算几次?
- 部分成功 / 降级返回:聚合接口 7 个下游 5 成 2 败,返回了降级数据,用户看到了"大部分内容"——这算成功还是失败?
- 口径谁定:SRE 定、产品定、还是联合定?有没有遇到过"SRE 说达标、业务说不达标"的拉锯?最后怎么收的?
- 你们有没有把 SLO 口径写进代码 / CI(比如 SLO 定义是一个 YAML / proto 文件,告警规则和 dashboard 都从它生成),还是散落在 Wiki 里靠人记?
我猜答案会按团队规模和业务类型分得很开。贴你们的实际口径和踩过的坑,比贴"最佳实践"有用得多。