第 16 / 23 篇

第15章 故障定位:沿提交边界寻找第一处分歧

让排查从问题对象开始

用户报告 id 一价格不对时,先确认源库当前值和最后业务修订,再沿连接器、Kafka、消费者、投影与查询依次追踪。不要先重启全部组件,因为重启可能改变现场并增加重复,且无法回答哪一层最先偏离事实。一个稳定对象 id 比一个模糊的“同步不正常”告警更容易建立证据链。

源库侧检查真实行、事务提交与 binlog 配置。连接器侧检查任务状态、错误堆栈与源位点。Kafka 侧检查 topic、分区、键与目标记录。消费者侧检查组位点、历史表、最后投影 offset 和错误日志。查询侧检查世代选择与删除过滤。找到第一处缺失或错误的边界,才能选择合适恢复动作。

RUNNING 是必要条件,不是充分条件

Connect 的 connector 处于 RUNNING,不代表每个 task 都正常,也不代表业务数据已经完整到达。本实验最终同时检查连接器和全部任务的状态,并结合消息操作种类和完整对账。若任务失败但 connector 外层仍存在,只看一个顶层状态就会误判。

同样,Kafka 消费者进程活着可能只是持续轮询空 topic,也可能订阅了拼写错误的前缀。早期实验真实遇到过 topic 尚未创建时订阅失败,因此控制程序明确等待连接器数据 topic 出现。等待有时间上限,缺失会失败,不会把不存在的 topic 自动变成“无数据所以成功”。

这份固定镜像已观察到的启动提示

基线容器日志出现ConnectRestExtension插件发现错误,具体是io.debezium.connector.mysql.rest等MySQL、PostgreSQL、SQL Server和MongoDB扩展Provider未找到。该次固定Connect镜像的rest.extension.classes为空,实验只使用标准Connect管理API与MySQL源连接器;标准API、真实binlog数据路径和二十二项检查均实际通过。我们保留这些原始日志,没有把所有ERROR行过滤掉。

这个结论只限定于已观察的可选REST扩展发现提示,不能推广为任意ServiceConfigurationError或堆栈都可忽略。若标准API不可用、MySQL源插件未装载、任务不为RUNNING或消息缺失,实验仍须失败。升级镜像时应重新检查该提示是否变化,并继续验证实际数据路径,而不是根据旧报告静默豁免新错误。

从错误形状识别配置问题

真实 JSON 消息如果出现 schema 与 payload 包装,而消费者期待顶层 op,会报字段缺失。这通常提示 converter 配置或解析契约不一致,不能通过忽略所有缺少 op 的消息掩盖。应当保存收到的结构,确认有效配置,再更新配置或版本化解析器。

如果出现数据库唯一冲突,需要先判断它是预期去重还是意外键冲突。delivery_history 的 ON CONFLICT 是设计内路径;consumer_binding 的冲突则需要读取现有绑定并拒绝不匹配参数。把所有完整性错误统一吞掉,会让错误世代看起来消费完成,实际却没有任何文档。

把日志写成可关联的信息

有效日志至少带对象身份、topic、partition、offset、消费组与世代。涉及源位置时还要保留 binlog 文件与位置的命名空间。不要只打印“update failed”,也不要无差别输出包含密码的完整连接配置。教学证据中的固定本地密码没有生产价值,实际环境需要脱敏和秘密管理。

本实验消费者报告消息总数、新鲜数、重复数、操作计数和少量 source 样例,控制程序另存检查列表与容器日志。消息数量帮助发现路径是否发生,逐行比较负责最终内容。日志与报告互相补足,不能互相替代。

失败分类决定恢复方法

依赖启动失败通常先修环境;连接器权限不足先核对最小权限与快照要求;schema 不兼容先停在明确失败点并发布兼容修正;投影暂时不可用可以在未提交位点条件下重试;历史位点超出保留范围则需要重建决策。把这些情况都写成无限重启,会持续消耗资源却无法恢复缺失事实。

对于毒消息,生产可以建立有审计的隔离流程,但不能在没有业务决策时自动跳过。跳过意味着查询副本可能永远缺少该对象的某次状态;后续完整文档更新有时会修复,有时不会,尤其删除缺失可能长期残留。本书采用遇到不支持事件就失败的策略,没有实现死信队列,因此不会声称验证了隔离后继续处理的正确性。

一次故障的结束条件

修复后组件变绿只是开始。需要确认 backlog 下降、关键探针可见、删除路径正常,并执行对账或有边界的业务验收。若通过新世代重建恢复,还要确认查询实际指向新世代,旧版本没有被后台任务重新启用。最后保存产品版本、输入位置、恢复动作与验收结果,供下一次故障比较。

实验报告关联 GitHub run URL,使检查结果能够回到具体源码提交和运行环境。公开报告只使用合成数据,因此可以完整分享;生产报告需要限制敏感字段,但仍应保留足够的事件身份来重现判断过程。

本章练习

为“源库已删除,查询仍返回对象”写一份最短排查路径。每一步列出读取证据、可能结果和下一步,禁止用“重启试试”代替判断。再说明在哪一步可以区分连接器没发删除与查询忘记过滤。