背景
随着系统业务的不断发展,部分核心业务的数据规模愈发庞大,查询统计等场景愈发复杂,mysql的性能逐渐无法满足日常的使用需求,特别是各种维度的搜索场景。
这种情况下,一般都会选择将搜索的数据源从Mysql转移到ElasticSearch,但同时也需要面对两个数据源的数据如何同步问题。
方案
总的来说,数据同步方案基本分为"同步写"和"异步写"两个大方向,并在这两个大方向上进行具体实现,同时都伴随着各自的优缺点。
同步双写
同步双写,顾名思义,就是数据写入MySQL同时,需要调用ES进行数据写入,如下图:
优点:
- 实现简单;
- 相较于其他方案,数据实时性较高。
缺点:
- 代码耦合性强。
- 同步双写事务问题,性能较低。
- 系统可用性同时受多个数据源可用性影响,系统可用性降低;
为何强调该方案数据实时性高是相较于其他方案呢?
在默认情况下,ElasticSearch并非实时写入的,而是近实时,即对文档的修改,默认最多等待1s,就可以查询到。由于其他方案大多不是同步写,所以相对来说,本方案实时性较高。
异步双写
由于同步双写会造成系统可用性降低,那很容易想到优化方案,就是同步改成异步,如下图
关于该方案中的异步,其实有不同的实现方式,比如异步线程、异步消息订阅等实现方式。在实际工作中,一般基于消息中间件的异步消息订阅的方式来实现。
优点:
- 代码耦合性低,业务代码无需关注数据同步;
- 性能高,避免了双写的事务问题,系统可用性较高;
- 拓展性强,基于消息中间件的消息订阅,非常容易进行多数据源和异构数据的拓展。
缺点:
- 数据实时性相对同步写稍低。
- 引入其他中间件,增加系统复杂度。
定时同步
基于消息中间件的异步双写是个不错的方案,但是需要同时引入消息中间件,对于部分"小步快跑"的项目来说,增加了时间和金钱的成本,那么此时继续定时任务的数据同步,是个不错的临时选择。
定时任务同步的实现方式,是基于对MySQL表进行定时扫描读取数据后,写入到ElasticSearch中,如下图
优点:
- 实现简单,对原有代码无侵入性;
缺点:
- 实时性取决与定时任务的周期,实时性难以保证;
- 当对实时性有较高要求时,对MySQL会造成较大的压力,可能导致系统整体可用性下降(可将轮询方到MySQL从库在一定程度避免)。
binlog订阅同步
众所周知,binlog是MySQL的逻辑日志,可以用来进行数据的同步和复制,MySQL主从同步就是基于binlog日志实现的。那么,MySQL与ElasticSearch间的数据同步,是否也可以基于binlog日志呢,答案是可以的。
一般来说,该方案需要引入一个中间件工具,作用是伪装成MySQL从库,接收主库binlog,然后同步到的其他数据源,如MySQL、ElasticSearch、HBase等等。市面上常见中间件工具如Flink-CDC、Canal、Otter、DataX等等,其基本原理如下图。
如图所示,实际上,我们往往会将binlog中间件接收到的binlog数据,转换成异步消息后推向消息中间件,方便其他服务订阅消费。其实binlog订阅同步的方案,可以说是前面"异步双写"方案的升级版,其进一步将"数据同步"功能下沉,与业务代码进一步解耦,这也符合软件开发中的"单一职责"原则。
优点:
- 对业务代码的入侵极少,开发过程中无感知;
- 数据实时性较高;
缺点:
- 需要引入中间件,架构上增加了复杂度,且同时增加了维护成本;
总结
本文只对MySQL与ES数据同步实现方案的基本思路进行简单介绍,并未涉及具体业务场景的实践。在实际中,需要对业务场景进行分析,权衡利弊,选择适合自己的方案,并在具体的实现细节上进行调整。