MySQL与Redis/ElasticSearch数据同步解决方案

一、数据同步方式介绍

1.1 什么是数据同步?

数据同步:当数据库中的数据发生变化,需要保证数据库中间件(Redis和ES)的数据与数据库数据保持一致

1.2 数据库中间件数据同步常用方式

  1. Change Data Capture(CDC):使用CDC技术从数据库中捕获数据更改,并将更改的数据发送到ES。CDC可以监视数据库的事务日志或使用其他方法来检测数据更改,然后将这些更改同步到ES中。这种方法可以确保ES中的数据与数据库中的数据保持一致。

  2. 双写:在进行数据更改时,同时更新数据库和中间件(ES、Redis)。应用程序在更新数据库之后,直接将相同的更改发送到中间件。这种方法确保了在数据更改期间数据库和中间件之间的一致性,但需要增加应用程序的开发和维护复杂性。

  3. 定期同步:定期将数据库中的数据同步到ES中。可以使用定时任务或批处理作业定期将数据库中的数据导入ES。这种方法可能会导致ES和数据库之间的数据有一定的延迟,但可以确保最终一致性。

  4. 使用消息队列:将数据更改发送到消息队列,然后消费者应用程序将更改应用于数据库和ES。消息队列可以充当缓冲,以确保数据更改在数据库和ES之间传递,并最终保持一致性。

  5. 采用事件驱动架构:将数据库中的数据更改表示为事件,并使用事件驱动架构来处理这些事件。当数据更改发生时,触发相应的事件,然后使用事件处理程序将更改应用于数据库和ES。这种方法将业务逻辑与数据更改解耦,并支持更高度的可扩展性和灵活性。

无论选择哪种方法,都需要仔细考虑数据一致性和容错性。此外,必须监测和处理中间件和数据库之间的任何同步错误或故障,以确保数据的完整性和一致性。

二、数据双写/双删

2.1 数据双写同步实现

接口1:查询商品信息,使用redis做缓存

接口2:根据关键字搜索商品信息,使用es搜索引擎

接口3:添加新的商品,通过双写操作同步redis、es

  1. 整合MyBatis-Plus

    • 添加依赖
    • 配置数据源
    • 启动类添加@MapperScan
  2. 配置和es的数据源

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/your_database_name?charactorEncoding=utf-8
        username: your_mysql_username
        password: your_mysql_password
      redis:
        host: 192.168.0.1
        port: 6379
        database: 0
        password: your_redis_password
      elasticsearch:
        rest:
          uris: http://192.168.0.1:9200
          username: your_elasticsearch_username
          password: your_elasticsearch_password
    
  3. Spring容器注入ES的客户端对象

    @Configuration
    public class ESConfig {
    
        @Value("${spring.elasticsearch.rest.uris}")
        private String uris;
        @Value("${spring.elasticsearch.rest.username}")
        private String username;
        @Value("${spring.elasticsearch.rest.password}")
        private String password;
    
        @Bean
        public RestHighLevelClient getRestHighLevelClient(){
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"+uris);
            int index1 = uris.indexOf("://");
            int index2 = uris.lastIndexOf(":");
            String protocol = uris.substring(0, index1);
            String host = uris.substring(index1+3,index2);
            String port = uris.substring(index2+1);
            HttpHost httpHost = new HttpHost(host, Integer.parseInt(port), protocol);
            RestClientBuilder restClientBuilder = RestClient.builder(httpHost);
            RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
            return restHighLevelClient;
        }
    
    }
    
2.2.4 商品添加接口实现

保证redis和数据库数据的一致性:双写

@Override
public ResultVO<Product> saveProduct(Product product) {
    try{
        int i = productMapper.insert(product);
        if(i>0){
            String s = objectMapper.writeValueAsString(product);
            stringRedisTemplate.boundValueOps("product_" + product.getProductId()).set(s);
        }
        return new ResultVO<>(0,"添加商品成功",product);
    }catch (Exception e){
        e.printStackTrace();
    }
    return new ResultVO<>(1,"添加商品失败",null);
}

2.2 数据双写问题分析

2.2.1 采用双写实现数据同步问题分析

我们采用双写操作——更新数据库的同时更新redis,因为写操作在完成数据库后更新之后再更新redis

问题:如果在更新数据库成功之后和更新redis成功之前,并发的读操作依然会读取到redis中未更新的数据——不能完全保证redis和数据库的强一致性

解决方案:

  • 线程隔离(加锁),影响查询性能
  • 将双写变为先删后写

先删后写

2.2.2 采用先删后写实现数据同步问题分析

如果在修改线程删除redis之后写数据库之前,查询线程查询redis并查询数据库同时同步查询的数据到redis,在修改线程写数据库之后就会导致redis缓存数据与数据库数据不一致。

双删操作总结:

使用Redis做查询缓存,数据库更新操作保证Redis一致性:
- 新增:只写数据库
- 修改:删除redis——修改数据库——删除redis
- 删除:删除redis——删除数据库——删除redis
使用ES做搜索引擎,数据库更新操作保存ES一致性:
- 新增:插入数据库——插入ES
- 修改:删除ES——修改数据库——插入ES  (可以搜索不到,但是不能搜索到修改之前的数据)
- 删除:删除ES——删除数据库

三、CDC介绍

3.1 CDC概念

CDC,通过CDC工具监听数据库中数据的变化,同步更新到中间件

3.2 CDC实现方式

  • 基于查询——通过查询操作对比数据的变化
  • 基于binlog日志监听——需要MySQL开启日志监听功能

3.3 常见的CDC框架

  1. Canal:https://github.com/alibaba/canal

    canal [kə’næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费
    早期阿里巴巴因为杭州和美国双机房部署,存在跨机房同步的业务需求,实现方式主要是基于业务 trigger 获取增量变更。从 2010 年开始,业务逐步尝试数据库日志解析获取增量变更进行同步,由此衍生出了大量的数据库增量订阅和消费业务。

  2. Debezium:https://debezium.io/

  3. Flink CDC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值