数据库和 ES 同时保存商品数据,更新并发、消息乱序和补偿怎么处理?
我的判断
MySQL 做权威源,ES 通过带版本的可靠事件更新;消费端拒绝旧版本,失败可重试并由对账任务修复。
更新商品时不做“数据库提交后同步调用 ES”这种双写,因为任一边失败都可能不一致。会把商品变更和 outbox 放同一本地事务,或订阅 binlog,事件带 productId、version 和完整可索引快照。
ES 文档保存同一版本。消费者收到事件时只允许新版本覆盖旧版本,乱序的 v4 在 v5 之后到达会被拒绝;重复 v5 幂等。删除使用 tombstone 事件,也带版本,避免旧更新把已删除商品重新写回来。
失败事件进入重试和死信,告警必须包含业务 ID。后台对账按更新时间分片比较 MySQL 与 ES 的版本/摘要,发现差异后从 MySQL 重建文档。
索引重建时写入新索引,追平增量后校验数量和抽样,再原子切 alias。整个方案接受短暂延迟,但保证最终可证明地收敛。
容易答偏踩坑误区
- 用消息到达顺序代替业务版本。 重试和多分区会让旧消息覆盖新数据。
- 只做重试,没有死信和对账。 永久失败会悄悄积累。
- 删除不带版本。 迟到更新可能让文档复活。