用途:把 MySQL 数据可靠地落到 ES 检索索引里
| 方式 |
做法 |
一致性 |
风险 |
| 应用双写 |
业务代码里同时写 DB 和 ES |
依赖代码正确性 |
一处失败导致不一致;写放大;无重试则丢 |
| 异步事件 |
DB 事务 → 本地消息表/事务消息 → 消费者写 ES |
最终一致,可重放 |
需要幂等与延迟监控 |
| binlog CDC |
Canal / Debezium 监听 binlog → 管道 → ES |
与业务代码解耦,较完整 |
需处理乱序、结构变更、全量与增量衔接 |
| 定时批量 |
按更新时间扫描重灌 |
简单,可兜底 |
延迟高,删除需额外处理(软删或差集) |
实践组合:CDC/事件做主链路 + 定时对账做兜底 + 手动重灌工具做修复。
- 乱序覆盖:同一实体的两次变更顺序颠倒,ES 留下旧值。对策:按实体键串行投递;或用
_seq_no/外部版本/业务时间戳拒绝旧版本。
- 删除同步:物理删除在 binlog 里是 delete 事件(CDC 可捕获),定时扫描方案则需软删标记或全量差集比对。
- 关联字段:搜索索引常需要多表拼接(订单 + 商品 + 客户)。要么在写入侧组装(宽表/物化视图),要么冗余“搜索所需最小字段集”并定义失效链路(关联表变更要触发主文档重建)。
- 全量与增量衔接:先全量灌(低峰、副本 0、关 refresh),记录水位(binlog position / 时间戳),再从该位点接增量,最后比对抽样校验。
- 检索索引按查询视角设计,而不是照搬表结构:一行文档 = 一次搜索要返回的完整卡片。
- 高频过滤字段用
keyword + filter;全文字段用 text 并配中文分词。
- 大字段(正文、详情)可只存 DB,ES 存摘要与 ID,避免文档膨胀。
- 时间序列数据用别名 + 滚动索引(ILM),避免单索引过大。
| 指标 |
含义 |
| 同步延迟(lag) |
事件产生到 ES 可搜的时间,业务承诺的依据 |
| 失败与重试数 |
管道健康度 |
| 抽样一致性比对 |
定期随机抽 ID 比对 DB 与 ES 字段 |
| 全量对账差异数 |
兜底发现漏同步 |
| 文档数与主键数差异 |
粗粒度完整性 |
| 误区 |
修正 |
| 应用双写但不处理失败 |
必须有重试与对账,否则不一致静默累积 |
| 把 ES 当权威数据源 |
它是派生索引,必须可从源重建 |
| CDC 不做乱序保护 |
后写覆盖先写,出现“数据回退” |
| 索引结构照抄表结构 |
查询时多轮关联,性能与实现都差 |
| 无重建能力 |
一旦映射不合理或数据错乱就无法恢复 |
| 忽视 mapping 变更成本 |
改类型需 reindex,用别名切换设计好 |
- Debezium / Canal 官方文档(Outbox、事件路由)
- Elasticsearch 官方文档:Reindex API、Aliases
- Martin Kleppmann《数据密集型应用系统设计》第 3、11 章(派生数据与变更捕获)