先选服务边界,再算错误率

frontend → orders 调用链(orders 先调用 inventory,成功后再调用 external-stub)跨越多跳。Istio 的 HTTP 请求指标可以分别由客户端代理和服务端代理报告,reporter="source" 与 reporter="destination" 并不是两个互不重叠的用户请求集合。若把两侧 istio_requests_total 直接相加,或者把库存服务的请求数当成 frontend 对用户的请求数,分母从一开始就错了。

要回答“frontend 对用户的成功率”还是“inventory 入站调用的成功率”,先选择一个明确的边界,再固定 destination_workload、命名空间、reporter、窗口和所包含的 HTTP 状态。示例固定在 service-mesh-lab 命名空间;若采集端汇聚多个集群,还须按实际暴露的集群标签限定同一目标集群,并在三个选择器中保持一致。以下 PromQL 仅是待在冻结版本核对标签与指标类型后的查询示意,不是本站抓取到的值;它衡量的是指定服务入站 HTTP 尝试中代理观测到的 5xx 比率,不自动等于完整用户 SLO:

来源代理和目标代理可能分别报告同一次请求,计算 SLO 必须先确定一个观察边界

1
2
3
sum(rate(istio_requests_total{reporter="destination",destination_workload="inventory-v1",destination_workload_namespace="service-mesh-lab",response_code=~"5.."}[5m]))
/
sum(rate(istio_requests_total{reporter="destination",destination_workload="inventory-v1",destination_workload_namespace="service-mesh-lab"}[5m]))

这个式子要先防零分母,再约定是否把代理本地拒绝、网关失败与不经目标入站代理的请求计入 SLO。版本切换后 v1/v2 都要纳入相同边界,否则部署 v2 会让计算“凭空变好”。用一个时间点的 counter 差值算请求率也不够;Prometheus 的 rate 需要观察窗口和足够样本,采集间隔、重启与缺失抓取都须记录。

p99 不能从各实例的 p99 再平均

如果冻结版以经典直方图暴露 istio_request_duration_milliseconds_bucket,服务总体 p99 应先按相同观测边界汇总各实例的桶,再在累计分布上求分位数:

1
2
3
4
5
histogram_quantile(0.99,
sum by (le) (rate(istio_request_duration_milliseconds_bucket{
reporter="destination",destination_workload="inventory-v1",destination_workload_namespace="service-mesh-lab"
}[5m]))
)

单位是毫秒;桶插值得到的是估计值,并非第 N 个请求的精确耗时。若使用 native histogram 或部署版本改变了桶/名称,必须改用对应查询,不能照抄此式。客户端真实等待时间还包括目标服务外的排队、网络、前置跳数和可能的重试;库存服务的 p99 不能直接命名为“用户 p99”。

固定输入做正负对照

先发送带唯一 ID 的固定数量正常 quote,核对客户端完成数、各代理 reporter 维度计数、库存应用日志及采集到的样本窗口。负例需在隔离测试桩中新增可控的库存侧 5xx,再配置一次真实代理重试:把逻辑请求数、客户端最终响应、各上游尝试数分别汇总,说明哪种计数变大了;现有库存 GET /quote 尚无可控 5xx 接口,也不能拿第 01 篇的应用重发冒充代理重试。延迟负例使用已有 -quote-delay,同时核对客户端 deadline 与库存实际处理时间。以同样的时间窗口和查询范围比较,不把模拟的输入数当成采集系统已成功保存的样本数。

验收项 实际计数/窗口/版本
正常请求及两端 reporter 对照 NOT_RUN:无 Kubernetes/Istio/Prometheus
5xx 分母与重试尝试数 NOT_RUN
跨实例桶聚合及延迟对照 NOT_RUN

最后才谈标签基数:response_code、工作负载、来源/目标等维度可用于聚合,但不能把每次请求的 X-Request-ID 作为指标标签,否则每个请求新增时间序列;逐请求检索交给日志或追踪。若未冻结抓取端和保留策略,不能宣称上述查询已经得到可用 SLO。

练习与参考解答

  1. 客户端发 100 次,目的端指标有 103 次,能直接说丢了 3 次请求吗?参考解答:不能。先检查重试是否导致多次上游尝试、指标窗口和所选维度;用户完成数与代理尝试数不是同一分母。
  2. 两个库存实例 p99 分别为 10ms 与 100ms,平均值 55ms 是否为整体 p99?参考解答:不是。需要同一边界、同一桶配置、同一窗口下的桶数据聚合,再计算整体分位数。

从测量值到目标与错误预算

SLI 是按上述边界得到的测量值,SLO 则还需要目标与评估窗口。假设约定“frontend 在滚动 30 天内,合格用户请求的成功率至少为 99.9%”,并预先定义合格请求和成功响应,那么基于请求数的错误预算就是该窗口合格请求数的 0.1%。若合格请求为 100 万次,预算为 1000 次失败;已有 700 次失败时剩余 300 次。这是算术示例,不是本系列实测;按请求数定义的预算也不能直接换成停机分钟数。前面的 5 分钟错误率可用于短窗口观察,单凭它无法判定 30 天目标是否达成。库存某一跳的 p99 同样不能替代 frontend 的端到端延迟 SLI。目标、窗口与指标的定义见 Google SRE 的服务级别目标说明。

官方资料与系列导航

系列导航:22 访问日志怎样区分代理失败和业务失败 → 23 网格指标怎样用于 SLO(本文)→ 24 自动追踪为什么仍会断链。