发布管理:从"发版靠吼"到"可审计的发布流水线"

“这个版本谁批的?”“为什么紧急插了一个需求?”“回滚了怎么没人通知?”——发布是质量链路的最后一公里,也是信息最碎的一环:开发、测试、运维、产品各看各的,发布决策散落在群聊和口头里。这篇讲把发布变成"可审计的流水线":决策有记录、门禁有数据、回滚有预案、复盘有闭环。

一、发布的本质:一次风险决策,不是一次技术操作

1
2
3
4
5
6
7
8
9
"发版"常被理解成"把包部署上去"(技术操作)
实际是:"当前质量状态 × 业务紧迫度 × 风险敞口"的决策

发布决策三要素(每次发布必须显式回答):
1. 质量状态:门禁全过?遗留缺陷清单(含"不修的理由")?
2. 业务紧迫:为什么是现在?(发版窗口/运营活动/事故修复)
3. 风险敞口:本次改动 blast radius?灰度计划?回滚预案?

三者都写在"发布单"里——没有发布单的发布 = 没有发生的发布(出了事说不清谁批的)

二、发布单:一份文档对齐四个角色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# release/2026.05.15.yaml(发布单,平台生成 + 人工确认)
release:
version: 2026.05.15
type: 常规周更
window: 2026-05-15 20:00 - 22:00(业务低峰)

quality: # 测试侧填(数据自动带入)
gates:
L1 门禁: 全过(build #4821)
L2 集成: 612/612(smoke+api 档)
L3 回归: 1847/1850,3 失败均为已知问题 #4821/#4790/#4755
长稳: 72h 无异常(run: soak-0512)
混沌: ⏭️ 本次无架构变更,按季度计划 05-28 执行
known_issues: # 遗留缺陷 = 风险声明
- id: #4821
desc: 支付超时状态偶发错乱(0.3% 概率)
decision: 带病发布
reason: 有监控 + 自动对账兜底,修复在 05.22 版本
approved_by: 测试 owner(记录在案)

change: # 开发侧填
scope: 23 commits / 14 文件 / 影响模块:订单、消息
blast_radius: 订单支付链路(核心)+ 消息列表(一般)
new_dependencies:
config_changes:
- 支付超时 5s 8s(已评估:弱网场景,压测验证通过)

rollout: # 发布计划
canary: 1%(4h)→ 10%(24h)→ 50%(24h)→ 100%
gates_ref: canary/gates/gate-{1,2,3}.yaml
rollback:
plan: 配置开关切回旧版本(2 分钟)+ 数据兼容确认(无 schema 变更)
drill: 2026-05-10 已演练,实际耗时 3 12
owner: 值班 SRE @张三

approval: # 决策留痕
- 测试 owner: @李四 2026-05-15 14:00(附质量状态)
- 开发 owner: @王五 2026-05-15 14:10(附变更范围)
- 产品: @赵六 2026-05-15 14:30(确认业务窗口)
decision: GO

发布单的四个价值

  1. 决策留痕:谁批的、基于什么数据批的、带病发布的缺陷谁拍的板——事故复盘时"谁批的"30 秒查清;
  2. 风险显式化:"带病发布"从潜规则变成带审批的显式决策(known_issues 每条都要理由 + 批准人);
  3. 四角色对齐:测试看质量、开发看范围、产品看窗口、SRE 看回滚,一份文档四个视角;
  4. 回滚预案可验证:演练记录(实际耗时 3 分 12 秒)让"能回滚"从承诺变成事实。

三、发布门禁:数据说话,不拍脑袋

1
2
3
4
5
6
7
8
9
10
11
12
13
14
门禁分两级:
1. 硬性门禁(不过不发,无例外):
- P0/P1 缺陷清零(或带病发布审批链完整)
- @critical 用例 100% 通过
- 回滚预案存在且 ≤ 30 天内演练过
- 发布窗口内无其他变更(变更冻结)

2. 软性门禁(可豁免,但豁免留痕 + 补偿措施):
- 增量覆盖率 < 80% → 豁免需测试 owner 批 + 指定补测计划
- 长稳未完成 → 豁免需"架构变更评估:本次不涉及"声明
- 混沌未跑 → 同上

豁免机制的意义:没有例外的门禁会被"紧急发布"击穿(然后所有门禁都被击穿)
有留痕的豁免让"紧急"有成本(要拍板 + 补偿 + 周报可见)

四、发布日:变更冻结与"唯一事实源"

1
2
3
4
5
6
7
8
9
10
11
12
13
发布窗口(如周五 20:00-22:00)的规矩:
1. 变更冻结:冻结开始到全量完成,除发布本身任何变更不进生产
(配置变更/数据订正/其他 hotfix 一律排期到窗口外)
2. 唯一事实源:发布状态只看发布平台(不看群聊)
- 平台状态机:准备中 → 金丝雀中 → 10% → 50% → 全量 → 完成/已回滚
- 每个状态变更自动通知(钉钉/飞书):谁、什么时间、什么状态、附指标快照
- 群里的"我这边好了"不算数,平台状态才算数
3. 值班分工:发布日固定三角(测试/开发/SRE 各 1 人),
平台上一键看到"现在谁在岗"
4. 事故升级路径预演:
金丝雀指标越界 → 自动回滚(不用人决策)
业务指标异常 → 暂停放大,三角会商 10 分钟内决策(继续/回滚/观察)
决策超时未响应 → 默认回滚(安全侧默认值)

"决策超时默认回滚"是发布制度的安全哲学:发布日最贵的不是回滚,是"僵在中间状态"——半灰度挂着,所有人盯着大盘,谁都不敢拍板。

五、发布后 72 小时:观察期与复盘

1
2
3
4
5
6
7
8
9
10
11
12
13
发布后观察期(72h,自动):
1. 指标基线对比:新版本 vs 上一版本(同口径 72h 曲线)
2. 缺陷监听:新版本缺陷自动关联版本标签
3. 灰度拦截复盘:发布后 72h 发现的缺陷 vs 发布单 known_issues
——known_issues 没列出的"带病"缺陷 = 发布决策漏了风险

发布复盘(每次发布必做,1 小时封顶):
1. 门禁数据 vs 实际(门禁说全过,线上还是出了事?为什么?)
2. 时间线还原(平台状态机自动导出)
3. 改进项(≤ 3 个,带 owner 和期限,进跟踪表)
4. 月度汇总:发布成功率/回滚率/回滚耗时/带病发布缺陷复发率
——"带病发布缺陷复发率"是发布决策质量的终极指标:
拍板"带病发"的缺陷后来复发了几次?复发多了说明风险评估失准

六、和测试体系的其他部分

1
2
3
4
5
发布管理在体系中的位置:
- 门禁数据源:CI 流水线(L1/L2/L3)+ 长稳 + 混沌 + 灰度判据
- 缺陷管理:known_issues 的每条 = 缺陷单的引用 + 决策记录
- 度量:发布成功率/回滚率进质量看板,和缺陷趋势同屏
- 发布单 = 所有测试数据的"汇总结论页"(测试产出的最后一站)

七、小结

发布管理工程化四个支柱:发布单(四角色一份文档,决策留痕)、两级门禁(硬性无例外,软性豁免留痕)、变更冻结 + 唯一事实源(状态只看平台)、72h 观察 + 复盘(known_issues 对照,带病发布复发率)。核心转变:发布从"群里的集体吼一嗓子"变成"平台上的状态机"——每一次决策都有数据、有审批、有时间线、有复盘,出事了 30 秒还原现场,没出事也积累下一版的判断依据。