4. 基于调用链的错误SLI口径定义:如何通过Span的Error Tag或StatusCode定义请求成功率/错误率SLI

4.1 错误SLI的核心数据来源

在OpenTelemetry与Jaeger的调用链模型中,Span是记录请求处理状态的最小单元。判断一次请求是否“错误”,主要依赖Span携带的两个关键属性:

  • Status Code:Span的最终状态码,取值 Unset、Ok、Error。
  • Error Tag:布尔型标签 error=true,通常由SDK自动或手动设置。

错误SLI(Service Level Indicator)即基于这两个字段,统计“错误Span数 / 总Span数”或“错误请求数 / 总请求数”,从而得到请求成功率或错误率。

关键原则: 错误SLI的口径必须与业务语义对齐。并非所有 error=true 的Span都代表用户可感知的失败,例如4xx状态码在某些场景下属于正常业务逻辑。

4.2 错误判定字段对比

字段 类型 设置方式 典型值 适用场景
Status Code 枚举(Unset/Ok/Error) SDK自动设置或手动调用 span.setStatus() StatusCode.ERROR 明确区分成功/失败,适合后端服务
Error Tag 布尔(true/false) SDK自动捕获异常时设置,或手动 span.setAttribute("error", true) error=true 兼容旧版OpenTracing语义,适合异常捕获
推荐做法: 优先使用 Status Code 作为错误判定依据,因为它语义更清晰、标准化程度更高。Error Tag 可作为辅助信号,用于标记未抛出异常但业务逻辑失败的场景。

4.3 错误SLI口径定义流程

定义错误SLI需要经过以下步骤,确保口径可测量、可复现:

  1. 确定错误判定规则:选择基于 Status Code 还是 Error Tag,或两者组合。
  2. 定义错误Span范围:是否包含所有Span?还是仅限根Span(Root Span)或特定服务Span?
  3. 排除非业务错误:例如健康检查、探活请求、预发流量等,需通过标签或服务名过滤。
  4. 设定统计窗口:固定时间窗口(如1分钟、5分钟)或滑动窗口。
  5. 计算SLI值:错误率 = 错误Span数 / 总Span数 × 100%;成功率 = 1 - 错误率。
常见陷阱: 直接使用Jaeger UI中的“Error”筛选结果作为SLI数据源,可能包含重复计数或非业务错误,导致口径偏差。必须基于原始Span数据做二次清洗。

4.4 错误SLI口径定义示例(基于OpenTelemetry语义)

以下是一个典型的错误SLI查询逻辑(以PromQL或SQL风格描述):

-- 假设Span数据已存入ClickHouse或类似时序数据库
-- 统计每分钟的错误率(基于Status Code)
SELECT
    toStartOfMinute(Timestamp) AS minute,
    countIf(StatusCode = 'Error') AS error_count,
    count(*) AS total_count,
    round(error_count / total_count * 100, 2) AS error_rate_percent
FROM otel_spans
WHERE ServiceName = 'order-service'
  AND SpanKind = 'SERVER'          -- 只统计服务端Span
  AND Attributes['http.method'] != 'GET /health'  -- 排除健康检查
GROUP BY minute
ORDER BY minute DESC;

4.5 错误SLI口径基线校准要点

  • 基线校准周期:建议以7天或30天为窗口,计算历史错误率均值作为基线。
  • 异常阈值设定:基线 ± 3σ 或固定百分比(如错误率超过0.1%触发告警)。
  • 口径变更管理:每次修改错误判定规则后,需重新计算基线,避免新旧口径混用。
  • 多服务统一口径:不同服务可能使用不同的HTTP状态码语义,需在SLI计算层做归一化处理。

4.6 错误SLI口径定义流程SVG

错误SLI口径定义流程 错误SLI口径定义流程 原始Span数据 错误判定规则(Status/Error Tag) 过滤非业务流量(健康检查等) 统计窗口聚合(1min/5min) 输出错误率/成功率SLI

4.7 错误SLI口径基线校准示例(基于Jaeger数据)

假设我们有一个微服务 payment-service,需要定义其请求成功率SLI。以下是基于Jaeger调用链数据的口径定义示例:

维度 口径定义 说明
数据源 Jaeger Span(OpenTelemetry格式) 仅采集 SpanKind = SERVER 的根Span
错误判定 StatusCode = Error 或 error=true 两者满足其一即视为错误Span
排除规则 排除 http.target = "/health" 或 http.method = "OPTIONS" 避免探活和预检请求干扰
统计窗口 1分钟滑动窗口 每1分钟计算一次错误率
基线计算 过去7天同一小时的历史错误率均值 消除时间周期性影响
告警阈值 基线 + 3倍标准差 超过阈值触发告警
实战建议: 在Jaeger中,可以通过 tags.error = true 快速筛选错误Span,但建议同时检查 status.code 字段,避免遗漏手动设置 StatusCode.ERROR 但未打Error Tag的Span。

4.8 错误SLI口径定义中的常见误区

  • 误区一: 认为所有 error=true 的Span都代表用户请求失败。实际上,某些内部重试或补偿逻辑也会产生错误Span,但最终请求可能成功。
  • 误区二: 忽略 StatusCode = Unset 的Span。在OpenTelemetry中,Unset 表示状态未知,不应默认视为成功。
  • 误区三: 直接使用Jaeger UI中的“Error Rate”图表作为SLI。该图表可能包含所有Span类型,未做业务过滤。
  • 误区四: 口径变更后未重新校准基线,导致新旧口径混用,告警阈值失效。

4.9 错误SLI口径定义最佳实践

  1. 统一错误语义:团队内部约定 StatusCode.Error 为唯一错误判定标准,error=true 仅作为辅助标记。
  2. 分层定义SLI:为每个服务定义独立的错误SLI口径,因为不同服务的业务语义不同。
  3. 自动化口径校验:通过CI/CD流水线自动检查Span数据中的错误标记是否符合口径规范。
  4. 定期复盘口径:每季度或每次重大发布后,重新审视错误SLI口径是否仍然适用。
工具推荐: 使用OpenTelemetry Collector的 spanmetrics 处理器,可以直接在采集端生成基于Span的错误率指标,减少后处理复杂度。