2. MTTR复盘口径的构成:检测时间、响应时间、定位时间、修复时间、确认时间
MTTR(Mean Time to Repair,平均修复时间)是衡量故障处理效率的核心指标。在SLO违约根因定位场景中,MTTR复盘口径的精确拆解直接决定了Tempo查询优化的方向。若口径模糊,则无法精准定位瓶颈环节,优化无从谈起。
MTTR复盘口径由五个独立且连续的时间段构成,每个阶段对应不同的运维动作与数据源。下表列出了各阶段的定义、典型数据来源及在Tempo中的关键Span属性。
| 阶段 | 定义 | 典型数据来源 | Tempo关键Span属性 |
|---|---|---|---|
| 检测时间 | 从故障发生到监控系统发出告警的时间 | Prometheus告警事件、SLO燃烧率指标 | alert.triggered_at |
| 响应时间 | 从告警发出到SRE工程师确认接手的时间 | PagerDuty/On-Call轮值系统、值班确认记录 | incident.acknowledged_at |
| 定位时间 | 从接手到确定根因的时间 | Tempo Trace分析、日志聚合、指标关联 | root_cause.identified_at |
| 修复时间 | 从确定根因到修复措施生效的时间 | 变更记录、部署流水线、配置回滚日志 | fix.deployed_at |
| 确认时间 | 从修复生效到SLO指标恢复正常的时间 | SLO燃烧率恢复、错误率归零、延迟达标 | slo.recovered_at |
下图展示了MTTR复盘口径的完整时间线,清晰标出五个阶段的起止边界与衔接关系。
2.1 检测时间:从故障到告警的沉默期
检测时间反映监控系统的覆盖度与灵敏度。常见问题包括:
- 监控盲区: 关键路径未埋点,导致故障发生后无告警。
- 告警延迟: 聚合窗口过长或采集间隔过大,拉长检测时间。
- 误报过滤: 过于激进的去重策略可能将真实故障误判为抖动。
在Tempo中,检测时间可通过alert.triggered_at与故障发生时的首个异常Span时间戳之差计算。优化方向包括缩短Prometheus采集周期、启用SLO燃烧率告警。
2.2 响应时间:从告警到人工接手的交接效率
响应时间受值班机制、告警路由、工程师可用性影响。典型瓶颈:
- 告警风暴: 大量重复告警导致关键告警被淹没。
- 路由错误: 告警未正确分配给当值团队。
- 手动确认: 缺乏自动化确认机制,依赖人工操作。
Tempo可通过incident.acknowledged_at与alert.triggered_at之差计算响应时间。优化方向包括告警聚合、分级路由、自动确认。
2.3 定位时间:根因分析的黄金窗口
定位时间通常是MTTR中最长且最不可控的阶段。其构成包括:
- 数据拉取: 从Tempo查询相关Trace,加载Span数据。
- 关联分析: 将Trace与日志、指标、事件关联,缩小范围。
- 根因判定: 人工或自动化工具确定故障根因。
在Tempo中,定位时间对应root_cause.identified_at与incident.acknowledged_at之差。优化方向是提升Trace查询效率、预计算服务依赖图、使用Span属性过滤。
2.4 修复时间:从根因到措施生效
修复时间取决于变更流程、部署速度、回滚能力。常见场景:
- 代码修复: 需要提交PR、CI/CD流水线、灰度发布。
- 配置变更: 修改配置中心、重启服务。
- 资源扩容: 增加实例、调整限流阈值。
Tempo通过fix.deployed_at与root_cause.identified_at之差计算。优化方向包括自动化回滚、预置修复脚本、缩短部署流水线。
2.5 确认时间:修复后的SLO恢复验证
确认时间确保修复措施真正生效,SLO指标回归正常。关键点:
- 指标滞后: SLO燃烧率窗口可能延迟反映修复效果。
- 误判风险: 短期指标恢复可能掩盖潜在问题。
- 验证手段: 主动探测、错误率监控、延迟P99检查。
Tempo通过slo.recovered_at与fix.deployed_at之差计算。优化方向包括缩短SLO评估窗口、启用实时燃烧率仪表盘。
下图展示了五个阶段在Tempo Trace中的Span时间戳映射关系,帮助理解如何从Trace数据中提取各阶段耗时。
2.6 各阶段在Tempo中的查询实现要点
在Tempo中实现MTTR复盘口径,需要为每个阶段定义明确的Span属性与查询条件。以下是一个基于TraceQL的示例查询,用于提取某次故障的五个阶段时间戳:
{
// 检测时间:找到故障发生时的首个异常Span
fault_span = { .service.name = "checkout-service" && .status.code = 2 }
| by(.trace_id)
| min(.start_time) as fault_start
// 告警时间:找到对应的告警Span
alert_span = { .alert.name = "SLO_BurnRate" && .trace_id = fault_span.trace_id }
| min(.start_time) as alert_time
// 接手时间:找到值班确认Span
ack_span = { .incident.id = alert_span.incident_id && .event = "acknowledged" }
| min(.start_time) as ack_time
// 根因定位时间:找到根因分析完成Span
root_cause_span = { .trace_id = fault_span.trace_id && .root_cause.identified = true }
| min(.start_time) as root_cause_time
// 修复时间:找到修复部署Span
fix_span = { .trace_id = fault_span.trace_id && .deployment.status = "success" }
| min(.start_time) as fix_time
// 恢复时间:找到SLO恢复Span
recover_span = { .slo.name = "checkout_latency" && .slo.status = "healthy" }
| min(.start_time) as recover_time
}
| compute(
detection_time = alert_time - fault_start,
response_time = ack_time - alert_time,
location_time = root_cause_time - ack_time,
fix_time = fix_time - root_cause_time,
confirm_time = recover_time - fix_time,
mttr = recover_time - fault_start
)
root_cause.identified_at时间戳,以保证数据准确性。
2.7 复盘口径的标准化要求
为确保MTTR复盘数据在不同团队、不同故障之间具有可比性,需遵循以下标准化规则:
- 时间戳精度: 所有阶段时间戳统一使用毫秒级Unix时间戳,避免时区与格式差异。
- 阶段边界定义: 每个阶段的结束时间点即为下一阶段的开始时间点,不允许出现时间重叠或间隙。
- 异常处理: 若某阶段无法获取有效时间戳(如自动修复未触发告警),需标记为
null并在计算中排除。 - 版本记录: 每次复盘需记录Tempo查询版本、Span属性定义版本,便于回溯与校准。