同步链路要解决什么
检索副本与主存储之间的同步有四种常见做法:应用双写、CDC 投递、消息队列中转、定时全量重建加增量补偿。选择哪一种是工程约束问题,但无论选哪种都要解决三件事:删除事件必须显式传递、乱序事件要有版本控制、随时保留从主存储全量重建索引的能力。另外要有位点监控,区分「真差异」与「还没同步到」。
方案对照
| 方案 | 优点 | 注意点 |
|---|---|---|
| 应用双写 | 链路短、实现直接 | 写失败要补偿;两条写路径逻辑必须对称 |
| CDC(binlog/oplog) | 不侵入业务、顺序有保障 | 组件多;存在重复投递与位点管理 |
| 消息队列中转 | 削峰、可多消费方 | 消息积压与顺序性需要专门设计 |
| 定时全量重建 + 增量 | 可作为兜底修复手段 | 全量期间增量要并行捕获,否则会漏一段 |
基本信息
| 投递语义 | 通常为至少一次,消费端必须幂等 |
|---|---|
| 顺序问题 | 用写入时间或单调版本号做比较,旧版本直接丢弃 |
| 删除处理 | 显式删除或软删除(status 标记后过滤),不能只同步更新 |
| 重建能力 | 保留从主存储按全量重建索引的脚本,并定期演练 |
| 监控项 | 同步位点延迟、失败重试数、批量写入错误数 |
用版本号消除乱序(ES external version 示例)
用版本号消除乱序(ES external version 示例)
curl -X PUT "localhost:9200/orders/_doc/1001?version=7&version_type=external" \
-H 'Content-Type: application/json' \
-d '{"orderId":1001,"status":"paid","updatedAt":"2026-10-12T10:00:00Z"}'
# 版本号低于文档当前版本时写入被拒绝(version conflict)
# 消费者遇到该错误直接跳过即可,无需重试,也不会覆盖新状态删除必须显式同步:软删除(保留文档并加标记,查询侧统一过滤)或直接发删除请求。只同步新增与更新而漏掉删除,会让搜索结果长期残留已删数据,用户可见且排查困难。
全量重建期间索引通常要临时切别名:先建新索引灌数据,数据校验通过后再把别名指过去,避免边重建边对外服务。