验收不是终结,是起点
很多团队把验收当成「项目结束的标志」,验收完就把文档锁进柜子。验收的真正价值在于:在系统上线前,明确知道哪些结论经过验证、哪些结论依赖假设、哪些假设需要在真实环境中进一步确认。
三卷书的所有结论,可以分为三类:
| 类别 | 定义 | 处理策略 |
|---|---|---|
| 已验证 | 本机实验跑过,输出与预期一致 | 直接落地 |
| 依赖假设 | 实验条件与生产条件有差距,结论在假设成立时有效 | 上线后持续监控假设是否成立 |
| 待验证 | 需要真实环境数据才能确认 | 制定验证计划,排期执行 |
验收的目标不是消灭第三类,而是明确列出第三类有哪些。消灭第三类需要时间和资源,有些甚至永远无法完全消灭。
三卷能力矩阵
import java.util.*;
public class AcceptanceMatrix {
record Capability(String area, String v3) {}
static void printMatrix() {
List<Capability> caps = List.of(
new Capability("ISR 与副本", "△"),
new Capability("事务消息", "△"),
new Capability("消费者组重平衡", "△"),
new Capability("死信队列", "✓"),
new Capability("消费速率控制", "✓"),
new Capability("事件建模", "✓"),
new Capability("CQRS 投影", "✓"),
new Capability("Saga 编排", "✓"),
new Capability("Schema 演进", "✓"),
new Capability("Kafka Streams", "✓"),
new Capability("链路追踪", "✓"),
new Capability("平台治理", "△"),
new Capability("容量规划", "○")
);
System.out.println("=== 卷三能力矩阵 ===");
int verified = 0, assumed = 0, pending = 0;
for (Capability c : caps) {
System.out.println(c.area() + ": " + c.v3());
if (c.v3().contains("✓")) verified++;
else if (c.v3().contains("△")) assumed++;
else if (c.v3().contains("○")) pending++;
}
System.out.println("已验证=" + verified + ", 依赖假设=" + assumed + ", 待验证=" + pending);
System.out.println("结论: " + (pending == 0 ? "✓" : "○ 有条件通过"));
}
public static void main(String[] args) {
printMatrix();
}
}
本机实测:
javac --release 21 AcceptanceMatrix.java && java AcceptanceMatrix
预期输出:
=== 卷三能力矩阵 ===
ISR 与副本: △
事务消息: △
消费者组重平衡: △
...
容量规划: ○
已验证=9, 依赖假设=3, 待验证=1
结论: ○ 有条件通过
依赖假设说明:ISR、消费者重平衡基于本机单节点测试,生产多节点行为可能不同;平台治理基于经验未在多团队验证。
遗留风险清单
| 编号 | 风险描述 | 缓解措施 | 验证计划 |
|---|---|---|---|
| R-01 | 10 万+ 分区时控制器选举时间未验证 | 分区数控制在 5 万以内 | Q4 压测 |
| R-02 | 跨可用区网络延迟未量化 | 同 AZ 优先部署 | 生产灰度 |
| R-03 | Schema Registry 在 100+ 团队时性能未验证 | 缓存 + 批量注册 | Q3 验证 |
| R-04 | 百万级 msg/s 生产者配置未验证 | 分层 topic + 批量发送 | Q4 压测 |
| R-05 | 事件溯源持续运行 1 年后重放时间未验证 | 定期快照 + 增量重放 | 年度演练 |
每个风险都需要有影响评估、缓解措施、验证计划三个要素。没有验证计划的风险等于没管理。
验收的生命周期
验收生命周期包含四个阶段:
| 阶段 | 名称 | 做什么 | 产出物 |
|---|---|---|---|
| 1 | 预审 | 开发团队自查 | 预审报告 |
| 2 | 正式验收 | 架构师评审 | 验收结论 + 问题清单 |
| 3 | 修复 | 按清单修复 | 修复说明 + 验证数据 |
| 4 | 复验 | 只评未通过项 | 最终判定 |
预审报告应该包含「我确认以下项已经验证」的声明,签字即负责。正式验收不能在上线前一天才开始。复验只看不通过项,不重复过全部项。
验收的量化标准
| 验收项 | 不合格 | 合格 | 优秀 |
|---|---|---|---|
| 端到端延迟 p99 | > 5 秒 | 1-5 秒 | < 1 秒 |
| 消费者 lag | 持续增长 | 稳定但非零 | 趋近于零 |
| 投影新鲜度 | > 5 分钟 | 30 秒-5 分钟 | < 30 秒 |
| 故障恢复时间 | > 10 分钟 | 1-10 分钟 | < 1 分钟 |
| 数据一致性 | 存在不一致 | 不一致可检测 | 零不一致 |
大部分验收项应该在「合格」档。「优秀」是努力方向,不是硬性要求。
后续演进方向
第一阶段(0-6 个月):补齐验证缺口
- 压测环境验证 R-01、R-04(大规模场景)
- 生产灰度验证 R-02(跨 AZ 部署)
- 建立监控面板追踪 R-03、R-05 指标
第二阶段(6-12 个月):扩展能力边界
- Exactly-Once 语义在生产环境验证
- 事件溯源 snapshot 策略在生产验证
- 跨集群 MirrorMaker 2.0 配置优化
第三阶段(12-24 个月):架构升级
- 评估 Kafka 4.x KRaft 特性
- 评估 Apache Avro 替代 JSON
- 评估云原生 Kafka 迁移路径
每个阶段的开始条件都是上一阶段的验收通过。不能跳阶段。
验收的核心产出
验收会应该产出三份文档:
- 能力矩阵:三卷结论汇总,标注已验证/依赖假设/待验证
- 风险清单:每个风险的编号、描述、影响、缓解措施、验证计划
- 演进路线图:三阶段计划,每阶段的开始条件、验收标准、负责人
三份文档不是一次性的。能力矩阵每季度更新,风险清单每月回顾,演进路线图每半年评审。
验收从否则开始的三个信号
验收不是到了最后一天才开始,而是在开发过程中就要观察三个信号:
实验是否可复现:如果每次实验结果都不一样,说明实验条件控制不严格,结论不可信。
判据是否可验证:如果验收标准出现「基本稳定」「大致一致」这种模糊表述,需要改成量化值。
假设是否被记录:所有「在生产环境中可能不同」的地方,必须显式写成假设清单。
这三个信号如果没在开发阶段出现,验收时就会发现大量「原来没想到」的问题。
验收的持续性要求
验收不是「一次通过就结束」,而是持续的过程。系统上线后,新的使用模式、新的数据规模、新的业务需求都会让原来的验收结论失效。
持续验收的三个触发条件:
| 触发条件 | 示例 | 验收动作 |
|---|---|---|
| 架构变更 | 从单集群变为多集群 | 重新验证跨集群一致性 |
| 规模增长 | 消息速率从 1K 增长到 10K msg/s | 重新评估容量规划和 SLO |
| 版本升级 | Kafka 从 3.x 升级到 4.x | 重新验证所有实验 |
持续验收的成本比首次验收低,因为大部分项可以直接复用之前的结论,只需要验证变更影响到的部分。但没有持续验收机制,系统会逐渐偏离最初的验收状态,直到某次故障才发现问题。
验收文档的维护责任
三份验收文档必须有明确的维护责任人:
| 文档 | 维护人 | 更新频率 | 触发条件 |
|---|---|---|---|
| 能力矩阵 | 架构师 | 每季度 | 新的能力验证完成 |
| 风险清单 | 项目经理 | 每月 | 风险状态变化 |
| 演进路线图 | 技术负责人 | 每半年 | 阶段切换或优先级调整 |
维护责任不能是「大家共同维护」。共同维护等于没人维护。每个文档必须有唯一的 DRI(Directly Responsible Individual),变更需要经过这个人的确认。
验收的入口条件
验收不是随时都可以启动的。以下四个条件必须全部满足,才能进入正式验收阶段:
| 条件 | 要求 | 验证方式 |
|---|---|---|
| 功能完成 | 所有设计的功能已经开发完毕 | 功能测试通过率 100% |
| 文档就绪 | 架构文档、运维手册、操作指南已完成 | 文档评审通过 |
| 环境就绪 | 生产环境或等价的预生产环境已就绪 | 部署验证通过 |
| 监控就绪 | 关键指标已接入监控面板 | 告警规则已配置 |
如果四个条件中任何一个不满足,验收应该推迟。在条件不满足的情况下强行验收,会导致验收过程中发现大量「还没准备好」的问题,浪费评审时间。
风险的跟踪与关闭
风险清单中的每一项都需要定期跟踪。跟踪方式:
- 已关闭的风险:验证完成后,更新状态为已关闭,并附上验证报告编号。
- 缓解中的风险:缓解措施正在实施中,每月更新进展。
- 待处理的风险:尚未开始处理,需要排期。
风险不能长期停留在「待处理」状态。如果一项风险超过一个季度没有进展,需要重新评估其优先级——可能它已经变得不重要,也可能它已经被其他措施间接覆盖了。
验收的退出条件
验收以三种方式结束:
| 结果 | 条件 | 后续动作 |
|---|---|---|
| 通过 | 所有验收项达到「合格」标准 | 进入上线流程 |
| 有条件通过 | 有不超过 3 项「待验证」,其余全部合格 | 上线,但待验证项必须在 30 天内完成验证 |
| 不通过 | 有超过 3 项「待验证」,或有任何项「不合格」 | 修复后重新验收 |
有条件通过是实践中常见的结果。完美验收(所有项优秀)很少见,也不应该作为目标——它会无限延长验收周期,让系统迟迟无法上线。
验收的持续投入
验收不是免费的。一个完整的三卷验收需要投入以下资源:
| 投入项 | 时间 | 人力 |
|---|---|---|
| 预审准备 | 1 周 | 2 人(开发团队) |
| 正式验收 | 2 天 | 5 人(架构师 + SRE + 项目经理 + 开发 + 测试) |
| 修复 | 1-2 周 | 视问题数量而定 |
| 复验 | 1 天 | 3 人 |
| 文档维护 | 持续 | 每季度 0.5 人天 |
如果验收发现大量问题,修复时间可能延长到一个月。这是正常的——验收的价值就在于发现这些问题,而不是快速通过。
持续验收的投入更低,每次变更只需要验证变更影响的部分,大约 0.5-1 天。但没有持续验收,累积的问题会在某次大变更时集中爆发,修复成本呈指数增长。
验收与上线时间的关系
验收应该在上线计划确定后、实际上线前完成。推荐的timeline:
- T-4 周:启动预审,开发团队自查
- T-3 周:正式验收,发现问题
- T-2 周:修复问题
- T-1 周:复验,确认通过
- T 天:上线
如果 T-2 周修复不完,上线日期应该推迟。不能为了赶上线而压缩验收修复时间——上线后发现问题,修复成本是上线前的 10 倍以上。
验收文化的建立
验收不是技术问题,是文化问题。团队需要建立「先验收后上线」的共识。
本节判据
- 验收不是终结,是明确已知和未知的起点。
- 所有结论分为三类:已验证、依赖假设、待验证。
- 依赖假设的条件必须在生产环境中持续监控。
- 待验证项必须有验证计划,包括时间、资源、负责人、通过标准。
- 遗留风险必须有缓解措施和验证计划,不能仅记录。
- 验收标准必须量化,分不合格/合格/优秀三档。
- 本机实测:卷三 13 项能力中 9 项已验证,3 项依赖假设,1 项待验证。
- 后续演进分三阶段,每阶段开始前必须完成上一阶段验收。
- 验收会产出三份文档:能力矩阵、风险清单、演进路线图。
阅读导航:上一节 15.2 故障演练剧本 | 下一节 附录 A 术语表
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。