• Mysql和ES、Redis数据同步方案汇总


    前言

    我们一般会使用Mysql用来存储数据,用Es来做全文检索和特殊查询,用redis来做数据的缓存

    那么如何将数据优雅的从Mysql同步到Es以及redis呢?

    一、数据同步方案

    1.同步双写

    这是一种最为简单的方式,在将数据写到mysql时,同时将数据写到ES或者redis

    这个方法的缺点是代码严重耦合,需要手动维护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);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 优点:
      1、业务逻辑简单
      2、实时性高
    • 缺点:
      1、 硬编码,有需要写入mysql的地方都需要添加写入ES的代码;
      2、 业务强耦合;
      3、 存在双写失败丢数据风险;
      4、 性能较差:本来mysql的性能不是很高,再加一个ES,系统的性能必然会下降。
    • 双写失败风险,包括以下几种:
      1) ES系统不可用;
      2) 程序和ES之间的网络故障;
      3) 程序重启,导致系统来不及写入ES等。
      针对这种情况,有数据强一致性要求的,就必须双写放到事务中来处理,而一旦用上事物,则性能下降更加明显。

    2.异步双写(MQ方式)

    针对多数据源写入的场景,可以借助MQ实现异步的多源写入,这种情况下各个源的写入逻辑互不干扰,不会由于单个数据源写入异常或缓慢影响其他数据源的写入,虽然整体写入的吞吐量增大了,但是由于MQ消费是异步消费,所以不适合实时业务场景。

    在执行完向Mysql中写入数据的逻辑后,发送MQ,告诉消费端这个数据需要写入Es,消费端收到消息后执行向Es写入数据的逻辑。这个方式的优点是Mysql和Es数据维护分离,开发Mysql和Es的人员只需要关心各自的业务。缺点是依然需要维护发送、接收MQ的逻辑,并且引入了MQ组件,增加了系统的复杂度。
    在这里插入图片描述

    伪代码:

        @Transactional(rollbackFor = Exception.class)
        public boolean parseJdDb(String keyword) throws IOException {
            //向数据库中插入
            List<JdGoods> jdGoods = htmlParseUtil.parseJd(keyword);
            //批量更新Mysql
            boolean b = this.saveBatch(jdGoods);
            log.info("异步同步至ES");
            rabbitTemplate.convertAndSend("es.exchange","es.renew.key", jdGoods);
            return b;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    优点:
    1、性能高
    2、不易出现数据丢失问题,主要基于MQ消息的消费保障机制,比如ES宕机或者写入失败,还能重新消费MQ消息。
    3、多源写入之间相互隔离,便于扩展更多的数据源写入

    缺点:
    1、硬编码问题,接入新的数据源需要实现新的消费者代码
    3、系统复杂度增加:引入了消息中间件
    4、可能出现延时问题:MQ是异步消费模型,用户写入的数据不一定可以马上看到,造成延时。

    3.基于Mysql表定时扫描同步

    上面两种方案中都存在硬编码问题,也就是有任何对mysq进行增删改查的地方要么植入ES代码,要么替换为MQ代码,代码的侵入性太强。

    如果对实时性要求不高的情况下,可以考虑用定时器来处理,具体步骤如下:
    1、数据库的相关表中增加一个字段为timestamp的字段,任何crud操作都会导致该字段的时间发生变化;
    2、原来程序中的CURD操作不做任何变化;
    3、增加一个定时器程序,让该程序按一定的时间周期扫描指定的表,把该时间段内发生变化的数据提取出来;
    4、逐条写入到ES中。

    如下图所示:

    该方案的典型实现是借助logstash实现数据同步,其底层实现原理就是根据配置定期使用sql查询新增的数据写入ES中,实现数据的增量同步。

    具体实现可以参考:通过Logstash实现mysql数据定时增量同步到ES
    在这里插入图片描述

    优点:
    1、不改变原来代码,没有侵入性、没有硬编码;
    2、没有业务强耦合,不改变原来程序的性能;
    3、Worker代码编写简单不需要考虑增删改查;
    缺点:
    1、时效性较差,由于是采用定时器根据固定频率查询表来同步数据,尽管将同步周期设置到秒级,也还是会存在一定时间的延迟。
    2、对数据库有一定的轮询压力,一种改进方法是将轮询放到压力不大的从库上。

    业界目前较为流行的方案:Canal实现Mysql数据同步至Redis、Elasticsearch

    4.基于Binlog实时同步

    上面三种方案要么有代码侵入,要么有硬编码,要么有延迟,那么有没有一种方案既能保证数据同步的实时性又没有代入侵入呢?
    当然有,可以利用mysql的binlog来进行同步。其实现原理如下:
    在这里插入图片描述
    具体步骤如下:
    1) 读取mysql的binlog日志,获取指定表的日志信息;
    2) 将读取的信息转为MQ;
    3) 编写一个MQ消费程序;
    4) 不断消费MQ,每消费完一条消息,将消息写入到ES中。

    优点:
    1、没有代码侵入、没有硬编码;
    2、原有系统不需要任何变化,没有感知;
    3、性能高;
    4、业务解耦,不需要关注原来系统的业务逻辑。
    缺点:
    1、构建Binlog系统复杂;
    2、如果采用MQ消费解析的binlog信息,也会像方案二一样存在MQ延时的风险。
    在这里插入图片描述

    二、数据迁移同步工具选型

    数据迁移同步工具的选择比较多样,下表仅从 MySQL 同步 ES 这个场景下,对一些笔者深度使用研究过的数据同步工具进行对比,用户可以根据自己的实际需要选取适合自己的产品。

    特性\产品CanalDTSCloudCanal
    是否支持自建ES
    ES对端版本支持丰富度中 支持ES6和ES7高 支持ES5,ES6和ES7中 支持ES6和ES7
    嵌套类型支持join/nested/objectobjectnested/object
    join支持方式基于join父子文档&反查基于宽表预构建&反查
    是否支持结构迁移
    是否支持全量迁移
    是否支持增量迁移
    数据过滤能力中 -仅全量可添加where条件高 -全增量阶段where条件高 -全增量阶段where条件
    是否支持时区转换
    同步限流能力
    任务编辑能力
    数据源支持丰富度
    架构模式订阅消费模式 需先写入消息队列直连模式直连模式
    监控指标丰富度中 性能指标监控中 性能指标监控高 性能指标、资源指标监控
    报警能力针对延迟、异常的电话报警针对延迟、异常的钉钉、短信、邮件报警
    任务可视化创建&配置&管理能力
    是否开源
    是否免费否 是社区版、SAAS版免费
    是否支持独立输出否依赖云平台整体输出
    是否支持SAAS化使用

    总结

    本文主要对Mysql和ES进行数据同步的常见方案进行了汇总说明。

    1. 同步双写是最简单的同步方式,能最大程度保证数据同步写入的实时性,最大的问题是代码侵入性太强。
    2. 异步双写引入了消息中间件,由于MQ都是异步消费模型,所以可能出现数据同步延迟的问题。好处是在大规模消息同步时吞吐量更、高性能更好,便于接入更多的数据源,且各个数据源数据消费写入相互隔离互不影响。
    3. 基于Mysql表定时扫描同步 ,原理是通过定时器定时扫描表中的增量数据进行数据同步,不会产生代码侵入,但由于是定时扫描同步,所以也会存在数据同步延迟问题,典型实现是采用 Logstash 实现增量同步。
    4. 基于Binlog实时同步 ,原理是通过监听Mysql的binlog日志进行增量同步数据。不会产生代码侵入,数据同步的实时也能得到保障,弊端是Binlog系统都较为复杂。典型实现是采用 canal 实现数据同步。
  • 相关阅读:
    明解STM32—GPIO应用设计篇之API函数及配置使用技巧
    暑期JAVA学习(47)XML解析技术
    绿色低碳 数字未来-辽宁省建筑电气2023年学术年会-安科瑞 蒋静
    【C++】优先级队列priority_queue模拟实现&&仿函数
    iPhone苹果15手机怎么取消订阅付费的项目?
    基于VueCli创建自定义项目
    uniapp 点击 富文本元素 图片 可以预览(非nvue)
    搜维尔科技:使用 CyberGlove数据手套进行远程机器人遥操作
    【Web前端】标签大全HTML/CSS/JavaScript
    计算机毕业论文java毕业设计选题源代码基于javaweb实现的客运站网上售票系统
  • 原文地址:https://blog.csdn.net/Zyw907155124/article/details/133084794