概述

每个做过线上运维的人大概都经历过这个场景:凌晨三点被告警吵醒,一通操作止血恢复,第二天组织复盘,会上列了十几条改进措施,会议纪要发到群里,大家纷纷表示"收到"。然后呢?一个月后你翻出来看,真正落地的大概只有两三条,其余的全躺在某个文档里吃灰。更扎心的是,半年后类似故障又来了一次,复盘会上一翻历史记录,好家伙,上次就提过改进建议,就是没人跟进。

这不叫复盘,这叫走过场。

改进项跟踪(Action Items Tracking)解决的就是这个问题——把复盘会议上产出的改进清单,变成有负责人、有截止日期、有验收标准、能被持续追踪直到闭环的工作项。说白了,复盘的价值不在会议本身,而在会议之后的那三个月里,这些改进项到底执行了没有、执行到位了没有。

Google SRE Book 里有一句话大意是:复盘没有 action items 的故障,等于白复盘。但我觉得这话还差半句——有 action items 但没跟踪,一样白复盘。

这篇文章聊的就是改进项跟踪这件事怎么做。从改进项的分类和生命周期讲起,到跟踪工具选型,再到自动化提醒和度量指标,最后给一套可以直接落地的实践方案。

改进项是什么:从模糊建议到可执行任务

改进项不是建议

很多人把"改进项"和"建议"搞混了。复盘会上有人说"以后上线要多测试一下",这是建议,不是改进项。改进项必须是可执行、可追踪、可验收的具体任务。

一个合格的改进项需要回答五个问题:

要素说明反面示例正面示例
做什么具体的行动内容“加强监控”“为订单服务的下游调用增加超时熔断,超时阈值设为 3 秒”
谁来做明确到具体责任人“研发团队”“张三(订单服务 owner)”
什么时候完成有明确的截止日期“尽快”“2026-08-15 前”
怎么验收可验证的完成标准“优化好”“Prometheus 中出现 order_downstream_timeout_total 指标,且在压测环境验证熔断生效”
优先级P0/P1/P2 分级不标注“P1:影响范围是全量用户,需在两周内完成”

缺任何一个要素的"改进项",本质上都是空头支票。你没法跟踪一张空头支票。

改进项的分类

根据改进的对象和执行周期,改进项可以分为四类:

1. 技术修复类(Technical Fix)

直接改代码或配置就能解决的问题。比如修复一个 bug、补一段熔断逻辑、加一个监控指标。这类改进项执行周期短,通常几天到两周搞定。

示例:
- 修复 order-service 的 N+1 查询问题(P0,2 天内)
- 为 payment-gateway 增加限流中间件(P1,1 周内)
- 将 Redis 连接池从 lettuce 换成 jedis 并配置合理超时(P2,2 周内)

2. 流程改进类(Process Improvement)

不涉及代码,但需要修改工作流程或规范。比如上线审批流程增加灰度验证环节、值班手册更新操作步骤、变更窗口制度调整。这类改进项涉及跨团队协调,周期通常在 2-4 周。

示例:
- 修改发布流程,所有 P0 级变更必须经过灰度环境验证(P1,2 周内)
- 更新 oncall 值班手册,增加 Redis 集群切换的操作步骤(P2,1 周内)
- 制定配置变更审批制度,所有线上配置变更需双人复核(P1,3 周内)

3. 架构优化类(Architecture Optimization)

需要较大改动甚至架构调整才能根治的问题。比如引入消息队列解耦同步调用、拆分单体服务、建设多活容灾。这类改进项周期长,通常 1-3 个月甚至更久,需要拆解为子任务分批执行。

示例:
- 将订单服务的同步库存扣减改为异步消息驱动(P1,拆分为 5 个子任务,3 个月内完成)
- 核心交易链路多机房容灾建设(P0,拆分为 12 个子任务,6 个月内完成)

4. 知识沉淀类(Knowledge Documentation)

把故障中的经验沉淀为文档、培训材料或自动化脚本。比如编写 Runbook、录制故障复盘分享视频、开发自动化巡检脚本。

示例:
- 编写 Redis 集群脑裂故障的 Runbook(P2,1 周内)
- 将本次故障的排查过程整理为培训材料,在团队内分享(P2,2 周内)

改进项的优先级评估

优先级不能拍脑袋,要基于故障的影响和改进项的收益来定。我推荐用一个简单的评分矩阵:

评估维度分值说明
故障影响范围1-5全量用户=5,部分用户=3,个别用户=1
故障发生频率1-5每月多次=5,每季度=3,首次=1
修复成本1-51 天内=1,1 周内=3,1 个月以上=5
预防收益1-5可彻底消除=5,部分缓解=3,仅记录=1

总分 = (影响范围 + 发生频率) × 预防收益 / 修复成本

总分 ≥ 10 的标 P0,5-9 标 P1,< 5 标 P2。

这个公式不是金科玉律,但它能逼着你在定优先级的时候想清楚几个维度,而不是凭感觉说"这个挺重要的,标 P0 吧"。

改进项的全生命周期管理

一条改进项从诞生到闭环,要经历五个阶段。每个阶段都有明确的输入、输出和责任人。

阶段一:创建(Creation)

复盘会议结束时,每条改进项必须当场确认五个要素(做什么、谁做、何时完成、怎么验收、优先级)。当场确认很重要——散会后再线上补充,信息损耗至少 30%。

实际操作中,复盘会议的最后 15 分钟应该是专门留来做这件事的。主持人逐条念出改进项,确认责任人和截止日期,现场记录到跟踪系统中。

创建阶段的关键产出:每条改进项有唯一 ID、明确的责任人、截止日期、验收标准、优先级。

阶段二:执行(Execution)

责任人按计划执行改进项。这个阶段最大的风险不是做不好,而是压根忘了做。

改进项的执行阶段应该有可见性。具体来说:

  • 改进项被创建后立即进入"待开始"状态
  • 责任人开始执行后手动改为"进行中"
  • 每条改进项在截止日期前 7 天自动提醒一次
  • 逾期后自动升级通知(通知责任人的上级和 SRE 团队负责人)

别小看这些提醒。我见过太多改进项不是不想做,是负责人忙别的去了,压根忘了这回事。系统自动提醒的成本几乎为零,但挽回的改进项数量相当可观。

阶段三:验收(Verification)

责任人声称完成后,不能自动关闭。改进项必须经过验收才算闭环。

验收分两种:

自动验收:适用于有明确技术指标的改进项。比如"增加某服务的 P99 延迟监控",验收标准是 Prometheus 中能看到对应指标,这种可以用脚本自动检查。

人工验收:适用于流程类或文档类改进项。比如"更新值班手册",需要指定验收人(通常是 SRE 团队负责人或复盘会议主持人)人工审核。

验收不通过的改进项会被打回,重新进入执行阶段。这比直接关闭要严格,但能避免"嘴上说做完了,实际根本没落地"的情况。

阶段四:归档(Archival)

验收通过后,改进项进入归档状态。归档不等于删除,归档的改进项仍然可以被搜索和查询。

归档阶段的一个重要动作是更新知识库:将改进项的执行过程和结果沉淀到团队的故障知识库中,方便后续遇到类似问题时参考。

阶段五:复盘审计(Audit)

每隔一段时间(建议每季度),对归档的改进项做一次审计。审计的目标是回答两个问题:

  1. 这个改进项是否真正解决了问题?——看后续是否还有同类故障发生
  2. 改进项的投入产出比是否符合预期?——看实际成本和收益与创建时的评估是否匹配

审计结果用于优化改进项的创建质量。如果发现某类改进项反复创建但效果不佳,说明改进方向有问题,需要从根因层面重新思考。

生命周期状态机

把上面五个阶段整理成状态机:

待开始(Open)
   ├──→ 进行中(In Progress)
   │         │
   │         ├──→ 待验收(Pending Verification)
   │         │         │
   │         │         ├──→ 已完成(Done)──→ 已归档(Archived)
   │         │         │
   │         │         └──→ 打回(Rejected)──→ 进行中(In Progress)
   │         │
   │         └──→ 已取消(Cancelled)  ← 发现改进项不再需要
   └──→ 已逾期(Overdue)──→ 升级通知

每个状态转换都要有记录,包含时间戳和操作人。这样你在任何时间点都能看到一条改进项的完整流转路径。

跟踪工具选型:别用 Excel,也别造轮子

为什么 Excel 不行

很多团队的改进项跟踪还停留在 Excel 或 Google Sheets 里。一列写改进项内容,一列写责任人,一列写截止日期,一列写状态。看起来挺清楚,实际上问题一堆:

  • 没有状态流转约束,随便改
  • 没有自动提醒功能,过期了没人知道
  • 没有历史记录,改了什么完全无追溯
  • 多人协作冲突,最后谁也不知道哪个版本是最新的
  • 没有统计分析能力,改进项完成率靠手动数

Excel 适合做一次性记录,不适合做持续跟踪。改进项跟踪需要的是一个有状态机、有通知、有历史、有统计的系统。

工具对比

市面上能用来跟踪改进项的工具不少,选哪个取决于你团队的现状和预算。别一上来就追求"完美的改进项管理系统",先把已有工具用好。

工具优势劣势适用场景
Jira功能完善,状态机自定义强,与开发流程打通配置复杂,运维成本高已有 Jira 的中大型团队
GitHub Issues轻量,免费,可关联代码 PR状态管理弱,缺少统计小团队,开源项目
GitLab Issues类似 GitHub,有看板视图状态管理较简单使用 GitLab 的团队
PingCode / 飞书项目国产工具,中文友好生态不如 Jira 丰富国内团队
自研系统完全定制化开发维护成本高有专门工具团队的大厂

推荐方案:Jira + 自定义工作流

如果你团队已经有 Jira(大概率有),不需要引入新工具,用 Jira 的自定义工作流就能实现改进项跟踪。Atlassian 在自己的实践中正是用 Jira work items 来跟踪所有复盘改进项,确保它们被完成和审批(参考 Atlassian Incident Management Handbook)。

核心配置如下:

1. 创建改进项 Issue Type

Issue Type: Postmortem Action Item
自定义字段:
  - postmortem-id: 关联的复盘文档 ID
  - action-type: 技术修复/流程改进/架构优化/知识沉淀
  - verification-method: 自动验收/人工验收
  - verifier: 验收人
  - actual-completion-date: 实际完成日期

2. 配置工作流状态机

# Jira Workflow Definition(简化版)
transitions:
  - from: Open
    to: In Progress
    condition: assignee != null
  - from: In Progress
    to: Pending Verification
    condition: true
  - from: Pending Verification
    to: Done
    condition: verifier_approval == true
  - from: Pending Verification
    to: In Progress
    condition: verifier_approval == false
  - from: Open
    to: Cancelled
    condition: role == "SRE Lead"

3. 配置自动化规则

Jira Automation 可以实现自动提醒和升级通知:

# 逾期前 7 天提醒
rule: pre-deadline-reminder
trigger:
  - schedule: "0 9 * * *"
  - condition: duedate <= now() + 7d AND status != Done
action:
  - send_email:
      to: assignee
      subject: "改进项即将到期提醒"
      body: "改进项 {{issue.key}} 将在 {{issue.duedate}} 到期,请尽快处理"

# 逾期后升级通知
rule: overdue-escalation
trigger:
  - schedule: "0 10 * * *"
  - condition: duedate < now() AND status != Done
action:
  - send_email:
      to: [assignee, assignee_manager, sre_lead]
      subject: "改进项已逾期"
      body: "改进项 {{issue.key}} 已逾期 {{days_overdue}} 天"
  - transition_issue:
      to: Overdue

轻量级替代方案:GitHub Issues + Labels

没有 Jira 的团队可以用 GitHub Issues 实现轻量版改进项跟踪。核心思路是用 Label 表示状态,用 Milestone 表示截止时间,用 Issue Body 的结构化模板记录改进项信息。

改进项 Issue 模板

---
postmortem: INC-2026-0721-001
type: technical-fix
priority: P0
assignee: @zhangsan
due-date: 2026-08-04
verifier: @lisi
---

## 改进项描述

为订单服务的下游调用增加超时熔断,超时阈值设为 3 秒。

## 验收标准

- [ ] Prometheus 中出现 order_downstream_timeout_total 指标
- [ ] 压测环境验证熔断生效
- [ ] 代码已合并到 main 分支

## 关联复盘

- 复盘文档:[INC-2026-0721-001 复盘报告](link-to-postmortem)
- 故障时间:2026-07-21 02:30 - 03:15
- 影响:订单服务超时,全量用户 45 分钟

Label 设计

status/open          — 待开始
status/in-progress   — 进行中
status/verification  — 待验收
status/done          — 已完成
status/overdue       — 已逾期
status/cancelled     — 已取消

type/technical       — 技术修复
type/process         — 流程改进
type/architecture    — 架构优化
type/knowledge       — 知识沉淀

priority/p0          — P0 紧急
priority/p1          — P1 重要
priority/p2          — P2 一般

用 GitHub Actions 实现自动提醒也不复杂:

# .github/workflows/action-item-reminder.yml
name: Action Item Reminder
on:
  schedule:
    - cron: "0 1 * * *"  # 每天北京时间 9 点

jobs:
  check-overdue:
    runs-on: ubuntu-latest
    steps:
      - name: Check overdue action items
        uses: actions/github-script@v7
        with:
          script: |
            const issues = await github.rest.issues.listForRepo({
              owner: context.repo.owner,
              repo: context.repo.repo,
              labels: ['postmortem-action-item', 'status/open'],
              state: 'open'
            });
            
            const now = new Date();
            for (const issue of issues.data) {
              const body = issue.body || '';
              const dueMatch = body.match(/due-date:\s*(.+)/);
              if (dueMatch) {
                const dueDate = new Date(dueMatch[1].trim());
                const daysLeft = Math.ceil((dueDate - now) / (1000 * 60 * 60 * 24));
                
                if (daysLeft <= 0) {
                  await github.rest.issues.addLabels({
                    ...context.repo,
                    issue_number: issue.number,
                    labels: ['status/overdue']
                  });
                  await github.rest.issues.createComment({
                    ...context.repo,
                    issue_number: issue.number,
                    body: `⚠️ 此改进项已逾期 ${Math.abs(daysLeft)} 天,请尽快处理。`
                  });
                } else if (daysLeft <= 7) {
                  await github.rest.issues.createComment({
                    ...context.repo,
                    issue_number: issue.number,
                    body: `提醒:此改进项将在 ${daysLeft} 天后到期。`
                  });
                }
              }
            }            

这段脚本每天检查一次所有待办的改进项 Issue,到期前 7 天提醒,逾期后自动打标签并评论。简单粗暴但有效。

自动化验收:让脚本替你检查

前面说过,改进项验收分自动和人工两种。能自动验收的尽量自动验收,因为人工验收的瓶颈在于验收人——一个人要验收几十条改进项,最后大概率走个过场。

自动验收脚本设计思路

自动验收的核心是:把"验收标准"翻译成"可执行的检查脚本"。比如验收标准是"Prometheus 中出现 order_downstream_timeout_total 指标",检查脚本就是查一下 Prometheus 有没有这个 metric。

下面是一个用 Python 写的自动验收框架:

#!/usr/bin/env python3
"""
Postmortem Action Item 自动验收框架
"""

import json
import subprocess
import requests
from datetime import datetime, timedelta
from dataclasses import dataclass, field
from typing import List, Optional, Callable
from enum import Enum

class VerificationResult(Enum):
    PASSED = "passed"
    FAILED = "failed"
    ERROR = "error"

@dataclass
class ActionItem:
    """改进项数据模型"""
    item_id: str
    title: str
    assignee: str
    due_date: str
    priority: str  # P0 / P1 / P2
    action_type: str  # technical-fix / process / architecture / knowledge
    verification_method: str  # auto / manual
    verification_fn: Optional[Callable] = None
    status: str = "open"
    postmortem_id: str = ""
    
@dataclass 
class VerificationReport:
    """验收报告"""
    item_id: str
    result: VerificationResult
    message: str
    checked_at: str
    details: dict = field(default_factory=dict)

class ActionItemVerifier:
    """改进项自动验收器"""
    
    def __init__(self, prometheus_url: str):
        self.prometheus_url = prometheus_url.rstrip("/")
        self.reports: List[VerificationReport] = []
    
    def check_prometheus_metric(self, metric_name: str) -> bool:
        """检查 Prometheus 中是否存在指定 metric"""
        try:
            resp = requests.get(
                f"{self.prometheus_url}/api/v1/query",
                params={"query": metric_name},
                timeout=10
            )
            data = resp.json()
            return data.get("status") == "success" and len(data.get("data", {}).get("result", [])) > 0
        except Exception as e:
            print(f"Prometheus 检查失败: {e}")
            return False
    
    def check_jenkins_job_exists(self, job_name: str) -> bool:
        """检查 Jenkins 是否存在指定 Job"""
        try:
            result = subprocess.run(
                ["jenkins-cli", "list-jobs"],
                capture_output=True, text=True, timeout=10
            )
            return job_name in result.stdout.splitlines()
        except Exception as e:
            print(f"Jenkins 检查失败: {e}")
            return False
    
    def check_grafana_dashboard(self, dashboard_uid: str) -> bool:
        """检查 Grafana 仪表盘是否存在"""
        try:
            resp = requests.get(
                f"http://grafana.internal/api/dashboards/uid/{dashboard_uid}",
                timeout=10
            )
            return resp.status_code == 200
        except Exception as e:
            print(f"Grafana 检查失败: {e}")
            return False
    
    def check_github_pr_merged(self, repo: str, pr_number: int) -> bool:
        """检查 GitHub PR 是否已合并"""
        try:
            resp = requests.get(
                f"https://api.github.com/repos/{repo}/pulls/{pr_number}",
                timeout=10
            )
            data = resp.json()
            return data.get("merged", False)
        except Exception as e:
            print(f"GitHub PR 检查失败: {e}")
            return False
    
    def verify(self, item: ActionItem) -> VerificationReport:
        """执行验收"""
        if item.verification_method != "auto" or item.verification_fn is None:
            return VerificationReport(
                item_id=item.item_id,
                result=VerificationResult.ERROR,
                message="该改进项不支持自动验收",
                checked_at=datetime.now().isoformat()
            )
        
        try:
            passed = item.verification_fn()
            return VerificationReport(
                item_id=item.item_id,
                result=VerificationResult.PASSED if passed else VerificationResult.FAILED,
                message="验收通过" if passed else "验收未通过",
                checked_at=datetime.now().isoformat()
            )
        except Exception as e:
            return VerificationReport(
                item_id=item.item_id,
                result=VerificationResult.ERROR,
                message=f"验收脚本执行出错: {e}",
                checked_at=datetime.now().isoformat()
            )
    
    def batch_verify(self, items: List[ActionItem]) -> List[VerificationReport]:
        """批量验收"""
        reports = []
        for item in items:
            if item.status == "pending-verification":
                report = self.verify(item)
                reports.append(report)
                print(f"[{item.item_id}] {report.result.value}: {report.message}")
        return reports
    
    def generate_summary(self, reports: List[VerificationReport]) -> str:
        """生成验收摘要"""
        total = len(reports)
        passed = sum(1 for r in reports if r.result == VerificationResult.PASSED)
        failed = sum(1 for r in reports if r.result == VerificationResult.FAILED)
        errors = sum(1 for r in reports if r.result == VerificationResult.ERROR)
        
        summary = f"""
=====================================
  改进项自动验收报告
  生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
=====================================
  总计: {total}  通过: {passed}  未通过: {failed}  错误: {errors}  通过率: {(passed/total*100):.1f}%(仅统计可自动验收的改进项)
=====================================
"""
        for r in reports:
            status_icon = "✅" if r.result == VerificationResult.PASSED else "❌"
            print(f"  {status_icon} [{r.item_id}] {r.message}")
        
        return summary


# ============ 使用示例 ============

if __name__ == "__main__":
    verifier = ActionItemVerifier(prometheus_url="http://prometheus.internal:9090")
    
    # 定义改进项(实际应从 Jira 或 GitHub Issues 拉取)
    items = [
        ActionItem(
            item_id="AI-2026-0721-001",
            title="为订单服务增加超时熔断监控指标",
            assignee="zhangsan",
            due_date="2026-08-04",
            priority="P0",
            action_type="technical-fix",
            verification_method="auto",
            verification_fn=lambda: verifier.check_prometheus_metric("order_downstream_timeout_total"),
            status="pending-verification",
            postmortem_id="INC-2026-0721-001"
        ),
        ActionItem(
            item_id="AI-2026-0721-002",
            title="创建 Grafana 订单服务仪表盘",
            assignee="lisi",
            due_date="2026-08-11",
            priority="P1",
            action_type="technical-fix",
            verification_method="auto",
            verification_fn=lambda: verifier.check_grafana_dashboard("order-service-dashboard"),
            status="pending-verification",
            postmortem_id="INC-2026-0721-001"
        ),
    ]
    
    # 批量验收
    reports = verifier.batch_verify(items)
    
    # 生成报告
    print(verifier.generate_summary(reports))

这个框架的设计思路是:每条改进项在创建时指定一个验收函数(verification_fn),验收函数是一个返回 bool 的闭包,内部调用具体的检查逻辑。批量验收时遍历所有"待验收"状态的改进项,执行各自的验收函数,最后汇总报告。

实际使用时,验收函数可以覆盖这些场景:

  • 检查 Prometheus 指标是否存在
  • 检查 Grafana 仪表盘是否存在
  • 检查 Jenkins Job 是否存在
  • 检查 GitHub PR 是否已合并
  • 检查 Runbook 文档是否已创建
  • 检查 Alertmanager 规则是否已配置

能自动验收的改进项占多大比例?根据经验,大概 40-60%。技术修复类的改进项大部分能自动验收,流程改进和知识沉淀类的基本需要人工验收。但这个比例已经能显著减轻验收负担了。

度量改进项跟踪体系的有效性

跟踪体系建好了,怎么知道它有没有用?得用数据说话。

核心指标

1. 改进项完成率(Completion Rate)

改进项完成率 = 已完成的改进项数 / 总改进项数 × 100%

这是最基础的指标。但光看完成率不够——如果完成的都是 P2 的低优先级改进项,P0 的全逾期了,完成率再高也没意义。

所以完成率要按优先级拆分:

优先级目标完成率说明
P0≥ 95%紧急改进项必须几乎全部完成
P1≥ 85%重要改进项允许少量延期
P2≥ 70%一般改进项有合理的淘汰空间

2. 平均闭环周期(Mean Time to Close, MTTC)

MTTC = 所有已闭环改进项的(闭环日期 - 创建日期)之和 / 已闭环改进项数

MTTC 反映改进项从创建到闭环的平均耗时。按类型拆分:

  • 技术修复类:目标 MTTC ≤ 14 天
  • 流程改进类:目标 MTTC ≤ 30 天
  • 架构优化类:目标 MTTC ≤ 90 天
  • 知识沉淀类:目标 MTTC ≤ 14 天

3. 逾期率(Overdue Rate)

逾期率 = 逾期改进项数 / 总改进项数 × 100%

逾期率直接反映跟踪体系是否在发挥作用。如果逾期率长期高于 20%,说明跟踪体系形同虚设。

4. 同类故障复发率(Recurrence Rate)

同类故障复发率 = 复盘后 90 天内再次发生同类故障的次数 / 总复盘次数 × 100%

这是终极指标。如果改进项跟踪体系有效,同类故障的复发率应该持续下降。如果改进项完成率很高但复发率不降,说明改进项方向有问题——要么没找到真正的根因,要么改进措施治标不治本。

5. 验收通过率(Verification Pass Rate)

验收通过率 = 验收通过的改进项数 / 参与验收的改进项数 × 100%

如果验收通过率长期低于 80%,说明改进项的执行质量有问题——责任人声称完成了,但实际没达到验收标准。这可能意味着改进项的验收标准定得太高,也可能意味着执行过程缺乏有效跟进。

度量面板

用 Grafana 做一个改进项度量面板,包含以下面板:

{
  "dashboard": {
    "title": "改进项跟踪度量面板",
    "panels": [
      {
        "title": "改进项完成率(按优先级)",
        "type": "gauge",
        "targets": [
          {
            "expr": "action_items_completed{priority=\"P0\"} / action_items_total{priority=\"P0\"} * 100"
          }
        ]
      },
      {
        "title": "改进项 MTTC 趋势(按类型)",
        "type": "graph",
        "targets": [
          {
            "expr": "avg by (type) (action_item_mttc_seconds{status=\"done\"} / 86400)"
          }
        ]
      },
      {
        "title": "逾期改进项数量",
        "type": "stat",
        "targets": [
          {
            "expr": "count(action_items{status=\"overdue\"})"
          }
        ]
      },
      {
        "title": "同类故障复发率(90天窗口)",
        "type": "graph",
        "targets": [
          {
            "expr": "incident_recurrence_rate_90d * 100"
          }
        ]
      }
    ]
  }
}

这些数据从哪来?需要把改进项的状态数据推送到 Prometheus。如果用 Jira,可以写一个定时脚本拉取 Jira 中的改进项状态并转为 Prometheus 指标:

#!/usr/bin/env python3
"""
从 Jira 拉取改进项状态并推送 Prometheus 指标
"""

import requests
from prometheus_client import CollectorRegistry, Gauge, push_to_gateway

JIRA_URL = "https://jira.internal"
JIRA_USER = "metrics-reader"
JIRA_TOKEN = "your-token-here"  # 建议从环境变量读取

def fetch_action_items():
    """从 Jira 拉取所有改进项"""
    jql = 'project = SRE AND issuetype = "Postmortem Action Item"'
    headers = {"Authorization": f"Bearer {JIRA_TOKEN}"}
    
    items = []
    start_at = 0
    while True:
        resp = requests.get(
            f"{JIRA_URL}/rest/api/2/search",
            params={"jql": jql, "startAt": start_at, "maxResults": 100,
                    "fields": "status,priority,assignee,created,duedate,resolutiondate"},
            headers=headers,
            timeout=30
        )
        data = resp.json()
        items.extend(data.get("issues", []))
        if start_at + 100 >= data.get("total", 0):
            break
        start_at += 100
    
    return items

def push_metrics(items):
    """推送 Prometheus 指标"""
    registry = CollectorRegistry()
    
    # 按状态统计
    status_gauge = Gauge(
        "action_items_by_status", 
        "Action items count by status",
        ["status", "priority"],
        registry=registry
    )
    
    # 按类型统计
    type_gauge = Gauge(
        "action_items_by_type",
        "Action items count by type", 
        ["type"],
        registry=registry
    )
    
    # MTTC
    from datetime import datetime
    mttc_gauge = Gauge(
        "action_item_mttc_seconds",
        "Mean time to close in seconds",
        ["type"],
        registry=registry
    )
    
    for item in items:
        fields = item["fields"]
        status = fields["status"]["name"].lower().replace(" ", "_")
        priority = fields.get("priority", {}).get("name", "P2")
        
        status_gauge.labels(status=status, priority=priority).inc()
    
    push_to_gateway(
        "pushgateway.internal:9091",
        job="action-item-metrics",
        registry=registry
    )
    print(f"已推送 {len(items)} 条改进项指标到 Prometheus")

if __name__ == "__main__":
    items = fetch_action_items()
    push_metrics(items)

把这段脚本放在 cron 或 systemd timer 里每天跑一次,Grafana 面板上就能看到改进项的实时度量数据了。

常见踩坑与对策

坑一:改进项太多,根本做不完

复盘会议上大家热情高涨,一口气列了二十几条改进项。结果一周后发现根本做不完,士气受挫,后面干脆全放了。

对策:单次复盘的改进项控制在 5 条以内。超过 5 条的,强制要求排优先级,只跟踪 P0 和 P1。P2 的放进 backlog,不强制执行。改进项不在于多,在于能落地。

坑二:责任人写的是"团队"或"全体"

“团队"不是人。写给"团队"的改进项等于没写给谁。三个月后你问"这个做了没”,团队里每个人都觉得是别人的事。

对策:改进项的责任人必须是具体的一个人。一个人可能负责多条改进项,但一条改进项只能有一个责任人。如果确实需要多人协作,也要指定一个主负责人(Owner),其他人作为参与者。

坑三:验收标准模糊

验收标准写"优化好"、“加强监控”,验收的时候谁也说不清到底什么叫"好了"。

对策:验收标准必须是可验证的。能写脚本的写脚本验证,不能写脚件的至少要写明具体条件。比如"在 Grafana 中能看到 order-service 的 P99 延迟面板"就比"加强监控"好得多。

坑四:改进项和日常工作混在一起

改进项和日常的 bugfix、feature 开发混在同一个任务看板里,根本分不清哪些是复盘改进项,哪些是日常工作。改进项被淹没在日常任务中,自然没人跟踪。

对策:改进项用独立的 Issue Type(Jira)或独立的 Label(GitHub Issues)标记,在看板上单独成列。每周的 SRE 例会专门过一次改进项状态,而不是混在迭代计划会里顺便提一句。

坑五:复盘文化变成问责文化

复盘会开成了追责会,改进项变成了惩罚依据——“上次就说了要做这个,你怎么还没做?是不是要扣绩效?“结果下次复盘,大家尽量少提改进项,提了也尽量挑容易的做。

对策:复盘文化的核心是"blameless”——对事不对人。改进项逾期应该被追踪和改进,但追责的方式是分析"为什么没做到”(资源不够?优先级不对?技术方案有障碍?),而不是惩罚责任人。美图 SRE 团队总结了复盘的黄金三问:我们怎么做才能更快恢复?怎么做才能避免再次发生?有哪些好经验可以固化?(参考 美图 SRE 故障复盘经验总结)——这三个问题的答案才是改进项的来源,而不是对"谁犯了错"的追问。

坑六:改进项只做不审,做了等于没做

有些改进项表面上看完成了,但实际效果存疑。比如"增加监控指标"这条改进项,指标加了但没人看,告警阈值设得不合理,照样不起作用。

对策:在验收阶段增加"效果验证"环节。改进项闭环后 30 天,回头检查这个改进是否真的发挥了预期效果。比如加的监控指标是否在后续故障中被用到,更新的 Runbook 是否有人实际参考过。效果验证不需要每条都做,但 P0 改进项必须做。

团队实践建议

根据不同规模的团队,我给出三档实践建议:

小团队(1-10 人)

用 GitHub Issues 或飞书多维表格就够了。核心做到:

  1. 每次复盘最多 5 条改进项
  2. 每条有明确责任人和截止日期
  3. 每周站会过一次改进项状态
  4. 月底统计完成率,发到群里

不需要复杂的状态机,不需要自动化验收。轻量但不丢——关键是有人盯。

中型团队(10-50 人)

用 Jira 配置自定义工作流。核心做到:

  1. 改进项独立 Issue Type,独立看板列
  2. 自动提醒和逾期升级
  3. 技术修复类改进项尝试自动验收
  4. 每月生成改进项度量报告
  5. 每季度做一次改进项审计

大型团队(50+ 人)

需要完整的改进项管理体系。核心做到:

  1. 改进项管理系统与故障管理系统打通,故障创建时自动关联改进项
  2. 全自动验收覆盖 50% 以上的改进项
  3. Grafana 度量面板实时展示改进项状态
  4. 改进项完成率纳入团队 KPI
  5. 每季度组织改进项审计,评估改进效果
  6. 建立改进项知识库,沉淀历史经验

总结

故障复盘的真正价值不在于会议本身,而在于复盘之后的改进项能不能落地。改进项跟踪就是把"纸上的改进"变成"系统的改进"。

核心经验就几条:

  1. 改进项必须满足五个要素:做什么、谁做、何时完成、怎么验收、什么优先级。缺一个都不算合格的改进项。
  2. 用工具跟踪,别用 Excel。Jira、GitHub Issues 都行,核心是要有状态机、有提醒、有统计。
  3. 能自动验收的尽量自动。人工验收是瓶颈,把验收标准翻译成可执行的检查脚本,能大幅减轻负担。
  4. 用数据度量体系有效性。完成率、MTTC、逾期率、复发率——这四个指标能告诉你改进项跟踪体系到底在不在起作用。
  5. 保持 blameless 文化。改进项跟踪的目的是让系统更可靠,不是惩罚人。文化一旦变成问责,改进项质量会迅速劣化。

最后说一句实在话:改进项跟踪这件事没有高深的技术门槛,难的是持续执行。工具选得再好,流程设计得再漂亮,没人盯就是白搭。如果你们的改进项跟踪体系总是建了废、废了建,问题大概率不在工具上,而在团队对这件事的重视程度上。先让管理层认识到改进项跟踪的价值,后面的事情就好办了。

参考资料与致谢

本文在撰写过程中参考了以下资料,感谢原作者的贡献:

  1. Incident postmortems — Atlassian,阐述了用 Jira work items 跟踪复盘改进项以确保完成和审批的实践方法
  2. 故障复盘究竟怎么做?美图SRE结合10年经验做了三大总结 — 美图 SRE 团队,总结了复盘黄金三问(更快恢复、避免重复、经验固化)和故障定级标准
  3. IT运维事故复盘工具指南:从应急响应到体系化改进的全流程解析 — 腾讯云开发者社区,提出了结构化复盘框架和改进项跟踪机制
  4. 干货丨企业运维故障复盘步骤及改进方法 — 彭华盛,建立了围绕"复盘方式、时间轴、根因分析、改进跟踪、报告发布"六步骤的复盘改进方法
  5. 如何做一次高效的事故复盘? — 腾讯云开发者社区,分析了传统 Blame Game 式复盘的问题和改进项难以跟进的根因
  6. 系统故障工程师居然可以不背锅?看看几家大厂是怎么做到的! — TakinTalks 社区专家,提出了"不指责重改进"的故障文化和"允许犯错但不允许一错再错"的定责准则