1643 字
约 5 分钟
10
S16-A02 · 质量门禁与发布:测试策略、灰度与回滚验收
适用读者:要对"能不能发"负责的人(技术负责人、发布 owner)。
前置:S16-B04(E2E)、S16-A01(可观测性)、S17(服务发布)。
覆盖旧文:—(E 驱动)。方法论旁证:A-275 的"审查反馈提升"(把评审意见转成可执行规则)。
扩展点:E-S16-010(门禁阈值)、E-S16-011(回滚验收三条件)。
上一篇:S16-A01 · 可观测性架构:采样、成本、保留与故障域
下一篇:S16-X01 · 书目与工具清单。
1. 一句话结论
门禁不是"测试全绿",而是"每一类风险都有一个可自动判定的证据"。 覆盖率是必要但不充分的条件:它能挡住"没测",挡不住"测错"。
| 门禁写法 | 挡住什么 | 挡不住什么 |
|---|---|---|
| 行覆盖率 ≥ 60% | 大面积未测 | 断言恒真、mock 掉真实依赖 |
| 分支覆盖率 ≥ 50%(核心模块) | 未走的分支 | 跨组件契约 |
| 主干 E2E 全绿 | 系统级断裂 | 边界数据 |
| 架构规则脚本 | 依赖方向违规 | 设计不合理 |
| 性能基线不回退 > 10% | 性能劣化 | 容量上限 |
2. 门禁阈值:怎么定才不反噬(E-S16-010)
| 原则 | 说明 | 反例 |
|---|---|---|
| 分层设阈值 | 核心域(计费/库存)高,边缘模块低 | 全仓库统一 80% → 大量无意义断言 |
| 新增代码优先 | 对 diff 覆盖率设阈值(如新代码 ≥ 70%),存量不追溯 | 一次性给遗留代码补测试 → 造假 |
| 门禁必须可在 10 分钟内跑完 | 超过就被绕过 | 全量 E2E 进每个 PR |
| 门禁失败必须给"怎么办" | 报错指向规则与修复建议 | 只贴一堆红叉 |
# 示例:分层门禁(CI 片段,示意)
gates:
unit: { branch_coverage: 50, fail_on: new_code_below: 70 }
integration: { suites: ["*IT"], timeout: 10m }
e2e: { suites: ["e2e/smoke"], timeout: 15m } # 只在合并主干前跑
arch: { script: "tools/check-arch-rules.ts", fail_on: violation }
perf: { baseline: "p95.json", max_regression: "10%" }
判据:这套门禁在过去 3 个月挡住过几次真实缺陷? 一次都没挡 → 门禁是装饰。
3. 把评审意见转成规则(A-275 的"审查反馈提升")
原文的闭环是:人工评审发现的问题 → 能不能变成一条自动检查?
| 评审意见 | 可规则化? | 落地 |
|---|---|---|
| "渲染进程不能直接调 Node API" | ✅ | 静态检查脚本(B04 §3) |
| "这里要加超时" | ✅(部分) | 静态规则:HTTP 客户端必须设置 timeout |
| "异常要打日志" | ✅(部分) | 规则:catch 块内必须有 log.* |
| "这个设计不合理" | ❌ | 只能靠 ADR/评审 |
频率判据:同一类评审意见出现 3 次 → 就该写成规则;只出现 1 次 → 保持人工。
4. 灰度与回滚验收(E-S16-011)
4.1 灰度节奏(以 1% → 5% → 25% → 100% 为例)
| 阶段 | 观察窗口 | 放行条件 | 停止条件 |
|---|---|---|---|
| 1% | 30 分钟 | 错误率与基线持平、P95 不回退 > 5% | 任一指标超阈值 |
| 5% | 1 小时 | 同上 + 无新增告警类型 | 同上 |
| 25% | 2 小时 | 同上 + 下游依赖无异常 | 同上 |
| 100% | 24 小时 | SLO 达标 | 触发回滚 |
4.2 回滚验收三条件
| # | 条件 | 判定方式 |
|---|---|---|
| ① 可回 | 上一版本镜像/配置可用,且已验证可启动 | 预发跑过一次回滚演练 |
| ② 回得去 | 数据/消息兼容(无不可逆 schema 变更;消息可被旧版本消费) | 契约测试 + 双写/兼容窗口 |
| ③ 回得快 | 从决策到恢复 < 目标 MTTR(如 5 分钟) | 自动化脚本 + 权限预置 |
判据:没演练过的回滚等于没有回滚。 每条发布单上写清"回滚命令是什么、谁有权限、预计多久"。
4.3 不可逆变更的例外处理
| 变更 | 风险 | 处理 |
|---|---|---|
| 删列/改类型 | 旧版本读不到 | 三步走:加新列双写 → 切读 → 删旧列(隔一个版本) |
| 消息格式变更 | 旧消费者解析失败 | 加版本字段,消费者兼容双格式 |
| 缓存 key 变更 | 冷启动击穿 | 预热 + 限流 + 降级 |
5. 发布单模板(可直接抄)
# 发布单:order-service v1.8.0
## 变更范围
- 新增:库存预占接口(幂等键 = 订单号)
- 修改:支付超时 3s → 5s
## 证据
- [x] 单测:分支 58%,新代码 74%
- [x] 集成:*IT 全绿(Testcontainers MySQL 8.4)
- [x] E2E:smoke 3 条(下单/支付/查询)
- [x] 架构规则:通过
- [x] 性能:P95 与基线持平(±3%)
## 观测
- 关键指标:order_create_p95、payment_timeout_rate
- 告警:错误率 > 1% 或 P95 > 800ms 立即停止放量
## 回滚
- 命令:kubectl rollout undo deploy/order-service
- 数据兼容:本次无 schema 变更
- 演练:2026-10-28 预发已演练,恢复耗时 2m10s
6. 常见误区
| 误区 | 纠正 |
|---|---|
| "覆盖率越高越安全" | 覆盖率只证明"执行过",见 §1 表 |
| "灰度就是随机放量" | 灰度要有观察窗口 + 停止条件,否则只是"提前上线" |
| "回滚就是把镜像换回去" | 还有数据兼容与消息兼容(§4.2 ②) |
| "门禁越严越好" | 过严 → 被绕过;门禁必须"快、准、有指引" |
7. 自测
- 你的发布单里,"回滚"一栏写的是命令,还是"回滚即可"?
- 上一次回滚演练是什么时候?没演练过 → 条件 ① 不成立。
- 你的门禁在过去 3 个月挡住过几次缺陷?写不出 → 门禁需要重设。
8. 下一篇
S16-X01 · 测试与可观测性书目/工具清单 —— 把 A-1881 的测试书单按"读法"重组:什么时候读哪本、读到什么程度算够。
S16-A02 · 质量门禁与发布:测试策略、灰度与回滚验收
https://www.clxhxhhr.top/posts/5415/ 评论
0 条
还没有评论,先写一条吧。