用内容指纹构建增量同步:从全量扫描到变化集处理
发布时间:
许多同步任务表面上只是“定时调用接口并写入数据库”,真正困难的却是三个问题:如何判断内容是否真的变化、如何避免重复触发下游副作用,以及底表更新成功但通知失败后如何恢复。
内容指纹是一种简单但有效的基础能力。
先定义业务上的相同
不能直接对原始 JSON 字符串求 Hash。字段顺序、无意义空白或时间格式变化都可能产生不同结果。计算指纹前,应先完成规范化:
- 只选择会影响业务行为的字段;
- 对对象键排序;
- 明确数组是有序还是无序;
- 统一空值、时间与数字表达;
- 去除请求时间、追踪 ID 等易变元数据;
- 稳定序列化后计算 SHA-256。
这一步实际上是在定义系统的业务相等关系。
索引表不是业务快照
可以单独维护轻量来源索引,保存业务键、内容指纹、来源状态和通知状态。业务键不存在则插入并通知,指纹变化则更新并通知,完全一致则幂等跳过,来源失效则产生撤销语义。完整内容由消费方按 ID 回源获取,通知只携带业务键,从而降低消息体和协议耦合。
不要让通知失败变成永久丢失
典型故障窗口是:数据库更新成功,通知下游失败;下一轮指纹相同,被判定为 unchanged,变化从此无法再通知。
解决方法是把“内容是否变化”和“通知是否完成”建模为两个状态。通知重试耗尽后,将索引标记为“有效但待补偿”。下一轮即使指纹相同,也再次进入通知逻辑。
更完整的方案是事务 Outbox:业务更新与事件在同一事务提交,再由独立 worker 投递。规模较小时,状态字段加定向重放也可作为阶段性方案。
删除与自然过期需要对账
只处理接口返回的数据无法发现删除,还需要比较本轮看见的业务键与数据库中的有效业务键。明确删除、暂停、自然过期和过期后恢复有效的业务语义不同,应分别处理,不能统一当作一次普通更新。
两种 Hash 不应混用
复杂链路通常同时存在采集侧索引 Hash 和消费侧完整快照 Hash。它们的字段集合与生成时间不同。审批前可再次比较当前来源索引 Hash 与草稿保存的索引 Hash,阻止用户批准已经过期的内容。
全量扫描仍可能是 O(N),但昂贵的 AI 解析、人工审批和跨系统发布只需处理变化集合 O(ΔN)。内容指纹必须与规范化、业务键、通知补偿、失效对账和版本校验共同组成完整协议。
