连载中 15/20

数据同步:MySQL 到 ES 的四条路

2026-08-17 · 2293 阅读 · 0 评论 · 0 赞

最后一个架构问题

写入调优解决了「怎么写得快」,但「数据从哪来」还没系统化:商品主数据在 MySQL,ES 里的副本怎么保持一致?改个价格,ES 什么时候跟上?这是所有搜索系统的必答题。候选答案四条路:同步双写、异步双写、定时扫表、binlog 订阅。逐条走一遍,坑都标出来。

第一条路:同步双写,最直观也最脆

在业务代码里,写完 MySQL 紧接着写 ES。直观,但暗坑三连:一是失败处理难——ES 写失败要不要回滚 MySQL?跨库事务代价太大,不回滚就是脏数据;二是延迟耦合——ES 抖一下,下单主流程跟着抖;三是到处散落——每个写商品的入口都得记得写 ES,漏一处就不同步。老王第一版就是这条路,线上第一个客诉就是这么来的。

第二条路:异步双写,用 MQ 解耦

把「同步进 ES」改成「发一条商品变更消息」,由消费者去写 ES——这正好是消息队列系列里异步解耦的教科书场景。主流程只依赖 MySQL 和 MQ,ES 挂了消息堆着,恢复后接着消费。最终一致性替代了实时强一致,代价是引入了消息组件和「重试加幂等」的心智:消费者必须幂等(回扣第 12 篇的业务主键 upsert),消息顺序丢了就得靠带版本更新兜底。团队已有 MQ 基建时,这是性价比很高的默认选项。

第三条路:定时扫表,笨但稳

每分钟扫一次 update_time 大于上次水位的记录,推给 ES。实现一个下午就能上线,不侵入业务代码,失败重扫就行。短板也明显:延迟等于扫描间隔,分钟级起步;扫表靠 update_time 索引,大表翻页要小心深分页(第 10 篇的教训在这里重演);被物理删除的行扫不到,得配软删除标记。中小数据量、容忍分钟级延迟的报表型索引,这条路其实很够用。

第四条路:binlog 订阅,准实时的终极答案

MySQL 主从复制的原理第 10 篇(MySQL 系列)讲过:主库把变更写进 binlog,从库重放。既然 binlog 记录了一切变更,那就假装自己是个从库——Canal、Flink CDC 这类工具伪装成 MySQL 的从节点,拉 binlog 解析成结构化变更,投递给 ES。业务代码零侵入,延迟秒级,连物理删除都能捕获。代价是引入一套订阅组件的运维:位点管理、数据投递的幂等与顺序、binlog 格式必须 ROW——都是实打实的运维成本。

方案延迟侵入性适用
同步双写实时业务代码强侵入小系统,能接受一致风险
异步双写秒级只侵入发消息一处已有 MQ 基建的团队
定时扫表分钟级零侵入报表型索引,延迟不敏感
binlog 订阅秒级零业务侵入,组件运维成本高准实时大表,删除也要同步

老王的选择与不变的法宝

老王最后的选择是组合拳:全量重建走 _reindex 加导入三件套(第 12 篇),增量用定时扫表起步,等数据量翻倍再切 binlog 订阅。无论走哪条路,两条不变的法宝:一,ES 文档 ID 用业务主键,写入天然 upsert 幂等,重试乱序都不怕;二,定期比对 MySQL 与 ES 的数量和抽样内容,对账任务每小时跑一次,发现漂移自动触发局部修复——一致性不是设计出来的,是校验出来的。

小结

四条路一句话:同步双写别裸奔,异步双写配幂等,扫表稳但慢,binlog 零侵入但重运维。没有最好的方案,只有配得上你数据量和团队能力的方案。

数据管道通了,零件全齐了:分词、mapping、查询、评分、聚合、集群、分片、同步。最后一道工序是把它们组装成产品。下一篇讲搜索产品化:从搜索框到搜索系统的完整链路设计

503

10 年全栈工程师 · 503咖啡馆主理人

#Elasticsearch#数据同步#Canal#binlog#双写

评论 (0)

相关推荐

连载中 12/20

排查四件套:jstack、jmap、jstat、jcmd 的实战分工

jstack 看线程在干什么,jmap 看堆里装了什么,jstat 看运行时在变什么,jcmd 是统一入口。四把刀各管一段,配合着用没有查不动的现场。

#jstack#jmap#jstat#jcmd#排查工具
2026-09-16 · 3 阅读 · 0 评论 · 0 赞
连载中 11/20

GC 日志:把回收过程翻译成人话

一行 GC 日志里塞着七种信息:谁触发的、收了哪、停了多久、活了哪些。加上 -Xlog 配置,再加上日志分析工具,GC 不再是只能盯监控曲线的黑盒。

#GC日志#Xlog#日志分析#GC监控#Full GC排查
2026-09-16 · 13 阅读 · 0 评论 · 0 赞
连载中 10/20

ZGC:亚毫秒停顿是怎么炼成的

百 G 大堆停顿不到一毫秒,靠的是把搬家全部挪到并发阶段——着色指针让引用自带状态,读屏障让搬运中的对象依然可访问。代价是吞吐与内存,收益是停顿与堆大小解耦。

#ZGC#着色指针#读屏障#亚毫秒停顿#分代ZGC
2026-09-15 · 8 阅读 · 0 评论 · 0 赞