背景
Mysql和ES是两种不同类型的数据库,各自有不同的特点嗯会应用场景。
Mysql特点:结构化数据库,支持事务,稳定...
ES特点:半结构化/非结构化数据库,支持分词检索和全文搜索,支持海量数据查询...
数据同步方案
主要分为同步双写和异步双写
同步双写
同步双写:即将数据同时写入到Mysql以及ES
伪代码:
/**
* 新增商品
*/
@Transactional(rollbackFor = Exception.class)
public void addGoods(GoodsDto goodsDto) {
//1、保存Mysql
Goods goods = new Goods();
BeanUtils.copyProperties(goodsDto,goods);
GoodsMapper.insert();
//2、保存ES
IndexRequest indexRequest = new IndexRequest("goods_index","_doc");
indexRequest.source(JSON.toJSONString(goods), XContentType.JSON);
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
highLevelClient.index(indexRequest);
}
优点:
-
业务逻辑简单
-
实时性高
缺点:
-
硬编码问题,既要写mysql代码还要写es代码
-
业务耦合较高
-
存在双写数据丢失风险
-
性能较差,既要写入Mysql又要写入ES,尤其高并发下,本来Mysql性能就不是很高,还要写ES,性能更低
-
同时有一些潜在风险
-
服务器和ES之间的网络故障
-
ES不可用
-
基于MQ的异步双写
针对要多写入的场景,可以使用Mq来实现异步解耦,这样各个源的写入互补影响;同时使用了Mq,整体的吞吐量提高,但是由于异步消费,系统的一致性较低。
优点
-
性能高,吞吐量大
-
各个业务逻辑解耦,互不影响
-
不易出现数据丢失问题。基于Mq的消费保障机制,可以实现消费失败重试
缺点
-
硬编码问题,接入新的数据源就需要编写新的消费者代码
-
系统复杂度较高,引入了中间件mq
-
可能出现延迟问题,MQ是异步消费模型,用户写入的数据不一定立即看到,会造成延迟
基于binlog的异步双写
上述两种实现要么会对侵入代码,要么会造成延迟,可以使用binlog来进行同步
优点
-
没有侵入式代码,不需要硬编码
-
性能高
-
业务解耦,不需要关注原来的业务逻辑
缺点
-
binlog构建复杂
有时候不仅需要将数据插入到ES还同时更新Redis,可以使用mq监听解析binlog,也会存在延迟风险
使用cannal监听binlog同步数据到es
canal原理就是伪装成mysql的从节点,从而订阅master节点的binlog日志,主要流程为:
-
canal服务端向mysql的master节点传输dump协议
-
mysql的master节点接收到dump请求后推送binlog日志给canal服务端,解析binlog对象(原始为byte流)转成Json格式
-
canal客户端通过TCP协议或MQ形式监听canal服务端,同步数据到ES