数据库读写分离分案

环境:MySQL主从数据库。如需要搭建可参考上一篇文章:MySQL主从数据库简单搭建

数据库使用主从可确保数据一致性,示例是基于一个完整的项目之上做了一些修改,为测试效果直接连接了两个非主从配置的数据库,其中只有测试的数据表内容不同其余内容全部相同。

方案参考:MySQL读写分离的三种实现方案

一、应用层(动态数据源切换)实现

优点: 1、不需要引入中间件; 2、 理论上支持任何数据库;
缺点: 1、侵入性强; 2、 根据具体的 Service 方法是否会操作数据,注入不同的数据源;

1、引入动态数据源依赖

<dependency>
	  <groupId>com.baomidou</groupId>
      <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
      <version>2.5.5</version>
</dependency>

2、配置文件修改

spring:
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          type: com.alibaba.druid.pool.DruidDataSource
          url: jdbc:mysql://192.168.100.205:3306/mydb?serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
          username: root
          password: '123456'
          driver-class-name: com.mysql.cj.jdbc.Driver
          initial-size: 5 # 初始连接数
          max-active: 50 # 最大连接数
          min-idle: 5 # 最小空闲连接数
          validation-query: SELECT 1 # 验证连接是否有效的 SQL 查询语句
          test-while-idle: true # 空闲时验证连接是否有效
          test-on-borrow: false # 获取连接时验证连接是否有效
          test-on-return: false # 归还连接时验证连接是否有效
          time-between-eviction-runs-millis: 60000 # 连接回收的时间间隔
          min-evictable-idle-time-millis: 300000 # 连接在池中最小生存的时间
        slave_1:
          type: com.alibaba.druid.pool.DruidDataSource
          url: jdbc:mysql://192.168.100.5:3306/mydb?serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
          username: root
          password: '123456'
          driver-class-name: com.mysql.cj.jdbc.Driver
          initial-size: 5
          max-active: 50
          min-idle: 5
          validation-query: SELECT 1
          test-while-idle: true
          test-on-borrow: false
          test-on-return: false
          time-between-eviction-runs-millis: 60000
          min-evictable-idle-time-millis: 300000

3、ServiceImpl相关实现中添加注解,指定切换从数据库

@Override
public void getById() {
	userMapper.getCount();
}

@DS("slave")
@Override
public void getById2() {
	userMapper.getCount2();
}

由于在数据源中配置了primary: master,默认操作都会从主库执行,使用注解@DS切换数据源,此注解也可直接用于类文件上,同时存在方法注解优先于类上注解。

4、测试验证

两个方法的查询语句一样,但设置两个测试数据库查询的表的内容有所不同,如果能查出对应的值说明读写分离成功。
项目启动成功会打印日志:
项目启动成功打印日志

5、遇到问题

项目启动失败
1、如果启动失败,可能是由于修改数据库配置,部分配置文件不匹配,需要注释掉。
比如示例项目中有未修改之前的配置类。数据库配置类
2、SpringBoot 启动时自动配置数据库信息导致启动失败,项目启动类添加注解。

@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)

因为 DruidDataSourceAutoConfigure 在 DynamicDataSourceAutoConfiguration 之前会注入一个 DataSourceWrapper,会在原生的 spring.datasource 下找 url,username,password 信息,在启动类上排除掉自动配置类即可。
项目启动补充注解

二、ShardingSphere-jdbc 实现

优点: 1、做SQL解析,自动实现读写分离; 2、 将事务都管理起来;
缺点: 1、存在侵入性(需要配置在代码中);

ShardingSphere参考文档:ShardingSphere 文档
ShardingSphere源码:ShardingSphere源码

1、引入ShardingSphere的Jar包依赖

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.0.0-RC1</version>
</dependency>

2、配置文件修改

spring:
  shardingsphere:
    # 数据源相关配置
    datasource:
      # 数据源名称
      names: master,s1
      # MySQL master数据源
      master:
        # 数据库连接池
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.100.205:3306/shardingsphere_demo?serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
        username: root
        password: 123456
      # slave数据源
      s1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.100.5:3306/shardingsphere_demo?serverTimezone=GMT&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
        username: root
        password: 123456
    masterslave:
      load-balance-algorithm-type: round_robin
      name: ms
      master-data-source-name: master
      slave-data-source-names: s1

    # 其他属性
    props:
      # 开启SQL显示
      sql.show: true

3、测试验证

写好测试代码,简单的数据库操作查询、新增即可,主要是为了测试查询走从库,对数据库操作走主库。

启动成功,控制台会打印初始化了两个数据库:
启动成功控制台输出执行查询时,控制台输出:
在这里插入图片描述执行新增时,控制台输出:
在这里插入图片描述

4、遇到问题

1、如果是在原有项目上改数据库配置,记得将nacos中原有数据库相关配置注释掉,原有项目中数据库配置类相关内容也要注释掉。

2、最初使用的是 4.1.1 版本,启动服务总是报错启动失败。
pom依赖

Caused by: java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required
	at org.springframework.util.Assert.notNull(Assert.java:201)
	at org.mybatis.spring.support.SqlSessionDaoSupport.checkDaoConfig(SqlSessionDaoSupport.java:122)
	at org.mybatis.spring.mapper.MapperFactoryBean.checkDaoConfig(MapperFactoryBean.java:73)
	at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
	... 49 common frames omitted

上网找解决方案,最终处理是将版本降低了。
pom依赖
版本降低之后启动还有报错,根据报错信息又加了一个配置,最终启动成功。

spring:
  main:
    allow-bean-definition-overriding: true

参考推荐:【MySQL系列】真香!基于ShardingSphere-JDBC的MySQL读写分离

三、引入开源数据库中间件解决

第三种需要添加中间件,后续讨论时觉得可以暂时不需要读写分离,所以这个没有尝试搭建示例。

1、MySQL Proxy MySQL 官方出品的一个轻量级通用的数据库中间件
2、Mycat 高可用的大规模分布式数据库系统
3、Cobar 阿里云推出的基于 MySQL 的中间件
4、Atlas 360开源

部分介绍可参考:浅谈读写分离和几种常见的开源数据库中间件

补充
读写分离常见场景:

1、读写分离集群方式的本质就是把访问的压力从主库转移到从库,也就是在单机数据库无法支撑并发读写的时候,并且读的请求很多的情况下适合这种读写分离的数据库集群。如果写的操作很多的话不适合这种集群方式,因为你的数据库压力还是在写操作上,即使主从了之后压力还是在主库上和单机区别就不大了。
2、出现MySQL的性能瓶颈,需要考虑读写分离:
IO瓶颈由于磁盘读写速度远低于内存读写速度,导致大量磁盘IO操作会成为性能瓶颈。
CPU瓶颈在大量复杂查询时,CPU资源会被大量占用,影响数据库性

其他场景:

1、资源优化,读写分离可以使得主库专注于处理写操作和事务性的操作,从库则处理读操作。这样可以根据主从库的不同特性进行硬件和系统资源的优化配置。
2、数据备份和故障转移,这是一个间接作用。通过读写分离,可以实现数据的实时备份。当主库出现故障时,可以迅速切换到从库,保证服务的持续可用。

读写分离只能分担访问的压力,分担不了存储的压力,如果数据库表的数据逐渐增多,面对一张表海量的数据,查询还是很慢,所以如果表数据达到一定量级,还是得分库分表。一般是先优化一些慢查询,优化业务逻辑的调用或者加入缓存等,如果真的优化到没东西优化了然后才上集群,先读写分离,读写分离之后顶不住就再分库分表。

  • 31
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值