文章

MTTR 与 MTBF 体系详解

MTTR 与 MTBF 体系详解

一句话:MTTR 衡量”出了事多快能恢复”,MTBF 衡量”多久出一次事”——两者合起来描述系统的可靠性画像,是稳定性体系最核心的度量指标。

概述

SLO 回答”多稳才算稳”,MTTR/MTBF 回答”出了事怎么办、多久出一次”。它们是稳定性体系的两条腿:

  • MTBF(Mean Time Between Failures):平均故障间隔时间,越长越好 → 预防能力
  • MTTR(Mean Time To Recovery):平均恢复时间,越短越好 → 响应能力

关键认知可用性 = MTBF / (MTBF + MTTR)。提升可用性有两条路——拉长 MTBF(少出事)或缩短 MTTR(快恢复)。99.9% 可用性意味着每月允许 ~43 分钟故障,这 43 分钟就是 MTTR 的预算。

MTTR 分解:四个关键子指标

MTTR 不是单一数字,而是一条时间链:

graph LR
    FAIL[故障发生] -->|MTTD| DETECT[告警触发]
    DETECT -->|MTTA| ACK[人工响应]
    ACK -->|MTTI| IDENTIFY[定位根因]
    IDENTIFY -->|MTTR_restore| RESTORE[完全恢复]
    
    FAIL -.->|MTTR 总时间| RESTORE
子指标全称含义典型值优化方向
MTTDMean Time To Detect故障发生到告警触发1-5 min监控覆盖率、异常检测、SLO 燃烧率告警
MTTAMean Time To Acknowledge告警到 On-Call 开始处理2-10 min告警路由、值班轮换、升级策略
MTTIMean Time To Identify开始处理到定位根因5-30 min排查方法论、可观测性、工具链
MTTR_restoreMean Time To Restore定位根因到完全恢复5-60 min回滚、自愈、应急预案、灾备切换

MTTR = MTTD + MTTA + MTTI + MTTR_restore

各子指标的优化手段

MTTD 优化:
  ├── SLO 多窗口多燃烧率告警(MWMBR)→ 减少误报,快速捕捉真实故障
  ├── 黄金信号全覆盖(延迟/流量/错误/饱和度)
  ├── 异常检测算法(时序预测 + 动态阈值)
  └── 关键路径心跳检测(主动探活)

MTTA 优化:
  ├── 告警分级(Page vs Ticket)→ 只 Page 真正紧急的
  ├── Alertmanager 分组 + 抑制 → 防告警风暴
  ├── On-Call 轮换 + 升级策略 → 确保有人响应
  └── 移动端推送(PagerDuty / 飞书 / 企微)

MTTI 优化:
  ├── K8s 故障排查方法论(分层排查)
  ├── 分布式追踪(OpenTelemetry → Jaeger/Tempo)
  ├── 日志聚合 + 关联查询(Loki / ELK)
  ├── 指标→链路下钻(exemplar)
  └── RCA 方法论(5-Whys / 故障树)

MTTR_restore 优化:
  ├── 一键回滚(CI/CD 流水线内置)
  ├── 故障自愈(自动重启 / 自动扩容 / 自动切换)
  ├── 应急预案 Runbook(标准化操作步骤)
  └── 灾备切换(多 AZ / 多 Region failover)

MTBF 优化:减少故障发生频率

MTBF 的提升依赖预防体系建设

预防手段做法效果
变更管控灰度发布、评审机制、冻结窗口、自动回滚减少 60%+ 的人为故障
容量规划压测推演、资源预留、弹性伸缩、容量预警避免容量超限导致的级联故障
高可用架构冗余部署、多 AZ、故障转移、依赖降级单点故障不影响整体可用性
混沌工程主动注入故障,验证恢复能力提前发现隐藏风险
代码质量CI 门禁、自动化测试、静态分析减少代码缺陷上线
依赖治理依赖版本锁定、兼容性测试、替代方案避免上游变更引入故障

计算方法与实战

MTTR 计算

import datetime
from dataclasses import dataclass

@dataclass
class Incident:
    incident_id: str
    start_time: datetime.datetime   # 故障发生时间
    detect_time: datetime.datetime  # 告警触发时间
    ack_time: datetime.datetime      # 人工响应时间
    identify_time: datetime.datetime # 定位根因时间
    resolve_time: datetime.datetime  # 完全恢复时间

def calculate_mttr_metrics(incidents: list[Incident]) -> dict:
    """计算 MTTR 及其子指标"""
    if not incidents:
        return {}
    
    total = len(incidents)
    mttd = sum((i.detect_time - i.start_time).total_seconds() for i in incidents) / total
    mtta = sum((i.ack_time - i.detect_time).total_seconds() for i in incidents) / total
    mtti = sum((i.identify_time - i.ack_time).total_seconds() for i in incidents) / total
    mttr_restore = sum((i.resolve_time - i.identify_time).total_seconds() for i in incidents) / total
    mttr = sum((i.resolve_time - i.start_time).total_seconds() for i in incidents) / total
    
    return {
        "MTTD_sec": mttd,
        "MTTA_sec": mtta,
        "MTTI_sec": mtti,
        "MTTR_restore_sec": mttr_restore,
        "MTTR_sec": mttr,
        "MTTR_min": mttr / 60,
        # 找出最慢的环节
        "bottleneck": max(
            [("MTTD", mttd), ("MTTA", mtta), ("MTTI", mtti), ("restore", mttr_restore)],
            key=lambda x: x[1]
        )[0],
    }

MTBF 计算

def calculate_mtbf(incidents: list[Incident], 
                  window_start: datetime.datetime,
                  window_end: datetime.datetime) -> dict:
    """计算 MTBF"""
    total_window = (window_end - window_start).total_seconds()
    num_failures = len(incidents)
    
    if num_failures <= 1:
        return {"MTBF_sec": total_window, "note": "样本不足,仅一个故障窗口"}
    
    # MTBF = 总运行时间 / 故障次数
    # 总运行时间 = 窗口时间 - 总故障时间(MTTR 总和)
    total_downtime = sum(
        (i.resolve_time - i.start_time).total_seconds() for i in incidents
    )
    uptime = total_window - total_downtime
    mtbf = uptime / num_failures
    
    # 可用性
    availability = uptime / total_window
    
    return {
        "MTBF_sec": mtbf,
        "MTBF_hours": mtbf / 3600,
        "total_failures": num_failures,
        "total_downtime_sec": total_downtime,
        "uptime_sec": uptime,
        "availability": f"{availability * 100:.3f}%",
    }

SLO 与 MTTR/MTBF 的关系

SLO每月允许不可用MTBF 要求MTTR 要求
99%432 min每 3 天 1 次故障每次 43 min
99.9%43.2 min每月 1 次故障每次 43 min
99.95%21.6 min每月 1 次故障每次 21 min
99.99%4.32 min每季 1 次故障每次 4 min
99.999%0.43 min几乎不允许故障每次 26 sec

关键洞察:SLO 越高,MTTR 要求越苛刻。99.99% 意味着 MTTR 不能超过 4.3 分钟——这基本排除了人工介入,必须靠自愈 + 自动切换。

MTTR/MTBF 度量看板

Grafana Dashboard 设计

# MTTR/MTBF 看板关键 Panel
panels:
  - title: "MTTR 趋势(30 天滚动)"
    type: stat
    query: |
      # 基于 Alertmanager 告警记录
      avg_over_time(
        (time() - alert_start_timestamp{alertstate="resolved"})[30d:1d]
      )
  
  - title: "MTTR 分解(按子指标)"
    type: bargauge
    # MTTD / MTTA / MTTI / restore 各占多少
  
  - title: "MTBF 趋势(30 天滚动)"
    type: stat
    query: |
      # 总运行时间 / 故障次数
  
  - title: "可用性趋势"
    type: timeseries
    query: |
      # uptime / (uptime + downtime) * 100
  
  - title: "故障频次(按严重程度)"
    type: piechart
    # SEV1 / SEV2 / SEV3 分布
  
  - title: "Top 10 根因分类"
    type: bargauge
    # 按根因分类聚合 MTTR
  
  - title: "MTTR 瓶颈环节"
    type: gauge
    # 哪个子指标最慢

告警规则示例

# MTTR 超过 SLO 预算告警
- alert: MTTRExceedsBudget
  expr: |
    avg_over_time(
      incident_mttr_seconds[7d]
    ) > 1800  # 30 分钟
  for: 10m
  labels:
    severity: ticket
    team: sre
  annotations:
    summary: "MTTR 超过 30 分钟预算"
    description: "过去 7 天平均 MTTR = {{ $value }} 秒,超过 SLO 预算"

# MTBF 下降告警(故障频率上升)
- alert: MTBFDecreasing
  expr: |
    (
      count_over_time(alertmanager_notifications_total{alertstate="resolved"}[7d])
      >
      count_over_time(alertmanager_notifications_total{alertstate="resolved"}[7d] offset 7d)
    )
  for: 1h
  labels:
    severity: ticket
  annotations:
    summary: "故障频率上升,MTBF 下降"

常见问题 / 坑点

问题原因解决方案
MTTR 数据不准故障开始/结束时间记录不规范建立标准化时间戳采集(Alertmanager webhook + 工单系统联动)
只看总 MTTR 不看分解不知道瓶颈在哪必须分解到 MTTD/MTTA/MTTI/restore,找出最慢环节
MTBF 样本太少高 SLO 系统故障少拉长统计窗口(季度/年度),或用混沌工程主动”制造”故障样本
可用性计算忽略部分降级只算”全挂”才算故障定义清晰的”故障”口径:SLI 违反即算故障,不论是否全挂
MTTR 数据靠人工填记录不及时、不准从 Alertmanager + 工单系统自动采集,不依赖人工录入

实践:从零建设 MTTR/MTBF 度量

第 1 步:定义故障口径

"故障"定义:
  - SEV1:核心服务 SLI 违反(成功率 < SLO / 延迟 > SLO)
  - SEV2:非核心服务 SLI 违反 或 核心服务部分降级
  - SEV3:单实例故障 / 非用户可感知的内部异常

第 2 步:自动采集时间戳

# Alertmanager Webhook → 时间戳采集服务
from flask import Flask, request
import datetime

app = Flask(__name__)

@app.route("/webhook", methods=["POST"])
def collect_timestamps():
    data = request.json
    alert = data.get("alerts", [{}])[0]
    
    if data.get("status") == "firing":
        # 故障检测时间
        record_incident_start(
            alert_id=alert["fingerprint"],
            detect_time=datetime.datetime.now(),
            alert_name=alert["labels"]["alertname"],
            severity=alert["labels"]["severity"],
        )
    elif data.get("status") == "resolved":
        # 故障恢复时间
        record_incident_resolve(
            alert_id=alert["fingerprint"],
            resolve_time=datetime.datetime.now(),
        )
    
    return {"status": "ok"}

第 3 步:建立度量看板

在 Grafana 中创建 MTTR/MTBF 专项看板,数据源接 Alertmanager + 自建 incident 数据库。

第 4 步:定期回顾

周度回顾:
  - 本周 MTTR vs 上周 MTTR
  - MTTR 分解:哪个环节最慢
  - Top 3 根因分类

月度回顾:
  - MTBF 趋势
  - 可用性 vs SLO
  - Action Items 落地情况
  - 最差故障复盘

关联知识

参考资源

学习时间

内容日期状态
MTTR/MTBF 定义与计算2026-08-03完成:定义、分解、计算公式、SLO 关系
度量看板建设待实践
从数据到改进闭环待实践

状态

  • MTTR/MTBF 定义与计算公式
  • MTTR 四子指标分解
  • MTBF 优化手段
  • SLO 与 MTTR/MTBF 的关系
  • 计算代码示例
  • 度量看板设计
  • 实际落地度量体系