ShardingSphere-ShardingJdbc 读写分离

廉价感情. 提交于 2020-10-27 11:59:06

一、读写分离背景

分库分表虽然可以优化数据库操作,但是要实现高并发,主从架构就应运而生了。数据库的主从复制架构,将数据库的写操作定位到主库中进行,主库和从库之间通过异步复制、半同步复制保持数据一致。所有的读操作都在主库的N个从库上进行。通过负载均衡使得每一次查询均匀的落在每一个从库上。

一主n从,做读写分离(数据写入主库,通过mysql数据同步机制将主库数据同步到从库–>程序读取从库数据),多个从库之间可以实现负载均衡。次外,ShardingSphere-ShardingJdbc可手动强制部分读请求到主库上。(因为主从同步有延迟,对实时性要求高的系统,可以将部分读请求也走主库)
MySQL配置主从同步可参考另一篇博客:https://blog.csdn.net/u014553029/article/details/108832268

二、读写分离实现

2.1 环境准备

程序环境:SpringBoot+MyBatis-plus
数据库环境:

数据库ip 数据库 作用
127.0.0.1 ShardingSphere master
127.0.0.1 ShardingSphere1 slave1
127.0.0.1 ShardingSphere2 slave2

2.2 添加ShardingSphere依赖

<!--shardingsphere数据分片、脱敏工具-->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.1.0</version>
</dependency>

2.3 配置读写分离规则

#### spring  ####
spring:
  # 配置说明地址 https://shardingsphere.apache.org/document/legacy/4.x/document/cn/manual/sharding-jdbc/configuration/config-spring-boot/#%E6%95%B0%E6%8D%AE%E5%88%86%E7%89%87
  shardingsphere:
    # 数据库
    datasource:
      # 数据库的别名
      names: ds0,ds1,ds2
      # 主库1 ,master数据库
      ds0:
        ###  数据源类别
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://146.56.192.87:3306/shardingsphere?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: oyc
        password: oyc@123456
      # 从库1 ,slave数据库
      ds1:
        ###  数据源类别
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://146.56.192.87:3306/shardingsphere1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: oyc
        password: oyc@123456
      # 从库2 ,slave数据库
      ds2:
        ###  数据源类别
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://146.56.192.87:3306/shardingsphere2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: oyc
        password: oyc@123456

    # *** 数据库分库分表配置 start
    masterslave:
      # 查询时的负载均衡算法,目前有2种算法,round_robin(轮询)和random(随机),
      # 算法接口是io.shardingjdbc.core.api.algorithm.masterslave.MasterSlaveLoadBalanceAlgorithm。
      # 实现类有RandomMasterSlaveLoadBalanceAlgorithm 和 RoundRobinMasterSlaveLoadBalanceAlgorithm。
      load-balance-algorithm-type: round_robin
      name: dataSource
      # 主数据源名称
      master-data-source-name: ds0
      # 从数据源名称,多个用逗号隔开
      slave-data-source-names: ds1,ds2
    # *** 数据库分库分表配置 end

    props:
      # 打印SQL
      sql.show: true
      check:
        table:
          metadata: true
          # 是否在启动时检查分表元数据一致性
          enabled: true
      query:
        with:
          cipher:
            column: true

2.4 测试读写分离效果

(1)写入数据,都是写主库:

读写分离效果-写入数据

(2)读取数据,根据规则负载从从库选择读取;

读写分离效果-读取数据

2.5 强制读取主库数据

读延迟问题解决方案:
  刚插入一条数据,然后马上就要去读取,这个时候有可能会读取不到?归根到底是因为主节点写入完之后数据是要复制给从节点的,读不到的原因是复制的时间比较长,也就是说数据还没复制到从节点,你就已经去从节点读取了,肯定读不到。mysql5.7 的主从复制是多线程了,意味着速度会变快,但是不一定能保证百分百马上读取到,这个问题我们可以有两种方式解决:
  (1)业务层面妥协,是否操作完之后马上要进行读取
  (2)对于操作完马上要读出来的,且业务上不能妥协的,我们可以对于这类的读取直接走主库,当然Sharding-JDBC也是考虑到这个问题的存在,所以给我们提供了一个功能,可以让用户在使用的时候指定要不要走主库进行读取。在读取前使用下面的方式进行设置就可以了:


/**
 * 用户列表,强制路由主库
 */
@RequestMapping("ds0")
public List<User> userListDs0() {
    logger.info("********TestController userListDs0():强制路由主库");

    HintManager hintManager = HintManager.getInstance();
    List<User> users = userMapper.selectList(null);

    //清除分片键值,分片键值保存在ThreadLocal中,所以需要在操作结束时调用hintManager.close()来清除ThreadLocal中的内容。hintManager实现了AutoCloseable接口,可推荐使用try with resource自动关闭。
    hintManager.close();
    List<User> users1 = userMapper.selectList(null);
    users.addAll(users1);
    return users;
}

强制路由到主库:
强制路由到主库
强制读取主库结果:
强制读取主库内容
从上图可以看出,我们设置的强制读取主库之后,每次查询都是去获取主库的数据。



官网传送门:https://shardingsphere.apache.org/document/legacy/4.x/document/cn/manual/sharding-jdbc/usage/read-write-splitting/
源码传送门:https://github.com/oycyqr/springboot-learning-demo/tree/master/springboot-shardingsphere-load

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!