第 19 / 23 篇

第18章 恢复演练:把系统保证逐项验收

用一条完整时间线串起全书

实验首先创建源表和两千行合成商品,初始化空投影。连接器开始真实 initial 快照,控制程序观察实际快照 SELECT,在同一查询仍活跃期间完成插入、更新、删除。随后消费者读取 r、c、u、d 事件,把数据写入 live 世代,执行第一次完整对账。这个起点同时覆盖已有数据与并发增量。

接着同组从起点显式重放,要求全部记录被识别为重复,结果保持相等。三种错误绑定必须在处理前被拒绝。新的 crash 组在数据库提交后、Kafka 位点提交前进入屏障,控制程序检查两个存储的真实状态,再发送 SIGKILL。普通重启至少遇到一条重复,并最终得到正确 crash-gen 投影。

从停机恢复到结构迁移

下一阶段没有任何 live 消费者运行,源库执行一百次更新、一次删除和一次插入。控制程序先证明投影已经落后,再启动 main 组追赶,验证真实操作计数和完整内容。这个顺序避免“没有产生故障也通过”的空测试,让恢复前后的差异可见。

随后真实新增 note 列,更新一行,显式迁移 live 文档的 null 默认值,再消费新 binlog。对账要求全部行字段一致。最后创建独立重建连接器、新 topic、新消费组和新世代,从当前源库重新快照,验证重建结果与源表相等,同时旧 live 世代仍保留且内容一致。

每一项检查应当支持具体结论

快照查询前后观测支持写入交叠,操作计数支持实际经过四条事件路径,binlog 样例支持真实来源,事务历史与 broker 位点支持故障窗口,退出码支持真实强制终止,重复计数支持重投,完整对账支持最终集合相等,绑定拒绝支持参数不变量。任何一项都不能独自替代其他项。

例如最终对账相等,可能只是错误测试根本没执行更新;因此要检查操作路径。进程被杀,也可能还没有处理消息;因此要检查数据库提交和 broker 未确认。连接器运行,也可能订阅错表;因此要检查真实消息和源投影内容。把检查拆成这些独立证据,才能评估测试到底覆盖了什么。

初次运行的实际基线

本书早期完整基线在 Linux GitHub Actions 上运行,真实 MySQL 为八点四点十一,Debezium 为三点一点二 Final,PostgreSQL 为十七点十一。基线通过二十二项检查,集成本体约一百零三秒。最终出版运行还会重新执行并记录自己的时间与环境;这些数字用于说明实验确实发生,不是生产性能承诺。

镜像标签后来固定为该次运行取得的真实摘要,Kafka 版本还由容器内命令输出保存。Python 依赖固定版本。读者复现时应检查运行证据与下载包是否对应同一发布版本,不要把另一个分支上的报告当成当前源码已经通过的证明。最终 canonical 报告以下载区 validation 为准。

仍然没有被验证的故障

本书没有让 broker 多节点选主,没有制造 MySQL binlog 已被清理后的缺口,没有数据库断电,也没有跨机房分区。我们没有测试多分区重平衡、跨表事务可见性、主键迁移、任意 DDL、权限撤回和搜索引擎排名。真实单机实验能建立边界清晰的基础,不能凭绿色 CI 延伸成这些更大的保证。

这些限制不是让读者停止使用,而是帮助下一轮实验有明确目标。若部署环境最担心日志丢失,就优先演练连接器恢复失败与重建;若最担心跨租户泄露,就增加真实权限服务与查询拒绝;若最担心吞吐,就在保留正确性检查的前提下增加数据量和故障期间负载。

为团队建立周期演练

周期演练可以按风险挑选场景,每次保留源码版本、环境、故障触发点、观察证据和验收结果。避免只在上线前执行一次,之后依赖版本和配置不断变化却不再复查。镜像升级、连接器升级、字段变化、分区策略变化和历史清理都可能改变恢复假设。

演练结束时应回答三个问题:哪些数据已经证明正确,哪些路径仍未验证,下一次故障由谁根据什么证据决定回放或重建。一个可操作的恢复手册,比一页笼统的“支持高可靠同步”说明更有价值。系统的可信度来自这些可以重新产生的事实。

把恢复手册交给没有参与开发的人

一次有价值的交付评审,可以让另一位维护者只凭仓库说明与下载包重新运行。他应当能够找到入口、理解资源所有权、读出失败原因,并判断报告是否对应当前源码。如果必须依赖作者记忆中的隐藏命令或本机目录,恢复路径就还没有真正产品化。独立解压执行是其中一项检查,无法替代全部运维演练,但能及时暴露最常见的依赖遗漏。

同样,书稿中的每个保证都应当能指向代码和证据。遇到无法定位的句子,应当补实验、缩小结论或明确标记为设计讨论。技术内容的深度不来自承诺数量,而来自边界是否解释清楚,以及读者能否在自己的条件下重新检验。持续维护这样的对应关系,才让可重建从一句架构口号变成实际工程能力。

本章练习

选择一个本书未验证但与你的业务直接相关的故障,写出真实触发方式、预期损坏、需要保留的证据和通过条件。禁止只增加一个 mock 测试就声称完成集成覆盖;先说明测试与生产边界之间还有哪些差距。