首页/数据/NoSQL 速查/主存储到搜索索引的同步方案
选型与架构50 条

主存储到搜索索引的同步方案

检索副本与主存储之间的同步有四种常见做法:应用双写、CDC 投递、消息队列中转、定时全量重建加增量补偿。无论哪种都要处理删除事件与版本乱序,并保留从主存储全量重建索引的能力。

NoSQL 速查数据更新于 2026-10-13

同步链路要解决什么

检索副本与主存储之间的同步有四种常见做法:应用双写、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)
# 消费者遇到该错误直接跳过即可,无需重试,也不会覆盖新状态
删除必须显式同步:软删除(保留文档并加标记,查询侧统一过滤)或直接发删除请求。只同步新增与更新而漏掉删除,会让搜索结果长期残留已删数据,用户可见且排查困难。
全量重建期间索引通常要临时切别名:先建新索引灌数据,数据校验通过后再把别名指过去,避免边重建边对外服务。

易错点

  • 同步链路缺少版本字段:乱序到达的旧事件覆盖新状态,数据看起来同步成功实则回退
  • 忽略删除事件:搜索与缓存中长期存在已删数据,用户可见且难以定位来源
  • 只在全量重建时校验一致性:日常增量失败无人发现,差异累积到重建时才暴露
  • 双写两条路径逻辑不对称(只在一侧做字段裁剪或转换):长期积累出难以解释的字段差异

数据来源与参考

  • Elasticsearch Guide: Indexing and versioning
  • Debezium Documentation: Connectors
  • MongoDB Manual: Change streams
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌