ShardingSphere数据库读写分离

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
传统型负载均衡 CLB,每月750个小时 15LCU
简介: 最近这段时间来经历了太多东西,无论是个人的压力还是个人和团队失误所带来的损失,都太多,被骂了很多,也被检讨,甚至一些不方便说的东西都经历了,不过还好,一切都得到了解决,无论好坏,这对于个人来说也是一种成长吧,事后自己也做了一些深刻的检讨,总结为一句话“挫败使你难受,使你睡不着觉,使你痛苦,不过最后一定会使你变得成熟,变得认真,变得负责”,每次面临挫败,我都会告诉自己,这不算什么,十年之后,你回过头来看待这件事的时候,你一定会觉得,这算什么屁事。

码农在囧途


最近这段时间来经历了太多东西,无论是个人的压力还是个人和团队失误所带来的损失,都太多,被骂了很多,也被检讨,甚至一些不方便说的东西都经历了,不过还好,一切都得到了解决,无论好坏,这对于个人来说也是一种成长吧,事后自己也做了一些深刻的检讨,总结为一句话“挫败使你难受,使你睡不着觉,使你痛苦,不过最后一定会使你变得成熟,变得认真,变得负责”,每次面临挫败,我都会告诉自己,这不算什么,十年之后,你回过头来看待这件事的时候,你一定会觉得,这算什么屁事。


背景


在现在这个数据量与日俱增的时代,传统的单表,单库已经无法满足我们的需求,可能早期数据量不是很大,CRUD都集中在一个库中,但是当数据量 到达一定的规模的时候,使用单库可能就无法满足需求了,在实际场景中,读的频率是远远大于写的,所以我们一般会做读写分离,主库一般用于写,而从库 用于读,而主从分离有好几种模式。


一主多从


一主多从是只有一台主机用于写操作,多台从机用于读操作,一主多从是存在风险的,当主机宕机后,那么写服务就会瘫痪,本文我们主要说的是ShardingSphere读写分离, 而目前ShardingSphere只支持单主库,所以如果要保证业务的高可用,那么目前ShardingSphere不是很好的选择,不过希望ShardingSphere后面支持多主机模式。


多主多从


从上面的一主多从我们看出了它的弊端,所以为了保证高可用,我们可能需要多个主机用于写操作,这样当某个主机宕机,其他主机还能继续工作,ShardingSphere只支持 单主机。


ShardingSphere只需要简单的配置就能实现数据库的读写的分离,我们甚至感知不到是在操作多个数据库,极大的简化了我们的开发,但是ShardingSphere 不支持多主库,也无法进行主从数据库的同步。


ShardingSphere整合SpringBoot项目进行主从分离


ShardingSphere和SpringBoot能够很简单的进行组合,只需要简单的配置,ShardingSphere能够和主流的ORM框架进行整合,ShardingSphere会 从ORM框架中解析出SQL语句,判断是读操作还是写操作,如果是读操作,则会落到主库上,如果是读操作,那么ShardingSphere会使用对应的负载均衡算法负载到 对应的从库上面。


maven引入ShardingSphere starter


<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.1.2</version>
</dependency>


yml文件配置


names为数据库名称字符串,然后需要一个一个的进行配置JDBC连接,对于读写分离,我们需要关注rules下面的readwrite-splitting 通过load-balancers配置负载均衡策略,data-sources配置对应的读写库,目前ShardingSphere只支持单主库,多从库,如下我们写 库使用write-data-source-name,库为db1,读库使用read-data-source-names,库db2,db3,db4


spring:
  shardingsphere:
    datasource:
      names: db1,db2,db3,db4
      db1:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
        username: root
        password: qwer123@
        type: com.zaxxer.hikari.HikariDataSource
        maximumPoolSize: 10
      db2:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
        username: root
        password: qwer123@
        type: com.zaxxer.hikari.HikariDataSource
        maximumPoolSize: 10
      db3:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/db3?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
        username: root
        password: qwer123@
        type: com.zaxxer.hikari.HikariDataSource
        maximumPoolSize: 10
      db4:
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/db4?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
        username: root
        password: qwer123@
        type: com.zaxxer.hikari.HikariDataSource
        maximumPoolSize: 10
    rules:
      sharding:
      readwrite-splitting:
        load-balancers:
          round_robin:
            type: ROUND_ROBIN
        data-sources:
          read_write_db:
            type: Static
            props:
              write-data-source-name: db1
              read-data-source-names: db2,db3,db4
            load-balancer-name: round_robin
    props:
      sql-show: true


测试写操作。


因为写操作配置的数据库是db1,所以所有写操作都应该进入db1,如下图所示,解析出来的ShardingSphere-SQL中显示的都是db1。



测试读操作


读操作配置的数据库是db2,db3,db4,配置的负载均衡算法是ROUND_ROBIN(轮询算法),所以查询请求会在三个库顺序查询。



ShardingSphere负载均衡算法


因为从库有多个,所以我们需要根据一定的策略将请求分发到不同的数据库上,防止单节点的压力过大或者空闲,ShardingSphere内置了多种负载均衡算法,如果我们想实现自己的 算法,那么可以实现ReadQueryLoadBalanceAlgorithm接口,下面我们列举几种来看下。


ROUND_ROBIN 轮询算法


配置负载均衡算法为轮询算法,那么所有请求都会均匀的分发到对应的数据库,这样,每台数据库所承受的压力都是一样的,轮询算法对应的实现类是RoundRobinReplicaLoadBalanceAlgorithm


public final class RoundRobinReplicaLoadBalanceAlgorithm implements ReadQueryLoadBalanceAlgorithm {
    private final AtomicInteger count = new AtomicInteger(0);
    @Getter
    private Properties props;
    @Override
    public void init(final Properties props) {
        this.props = props;
    }
    @Override
    public String getDataSource(final String name, final String writeDataSourceName, final List<String> readDataSourceNames) {
        if (TransactionHolder.isTransaction()) {
            return writeDataSourceName;
        }
        return readDataSourceNames.get(Math.abs(count.getAndIncrement()) % readDataSourceNames.size());
    }
    @Override
    public String getType() {
        return "ROUND_ROBIN";
    }
    @Override
    public boolean isDefault() {
        return true;
    }
}


RANDOM 随机算法


如果使用随机算法,那么请求过来以后就会随机的分发到其中的一个数据库上面,使用随机算法可能会导致请求的分发不均匀,可能某一台 接受到了大量的请求,某一台接受到的请求相对来说较少。


WEIGHT 基于权重的算法


基于权重的算法需要做相应的配置,我们可以将某一台数据库的权重加大,某一台数据库的权重减小,这样,权重大的数据库 就会接收到更多的请求,权重小的接收到的请求就会比较少。


在ShardingSphere中自定义负载均衡算法


ShardingSphere中使用了大量的SPI,所以我们开发者可以自由的实现自己的规则,然后无缝的切换到自己的规则,我们可以实现自己的一套负载均衡算法,其实ShardingSphere内置的集中负载均衡算法完全能满足数据库负载均衡,只不过为了更加深入的学习ShardingSphere,所以我们很有必要自己简单的实现一下。


下面我们简单的实现一下,我们就不去实现一些复杂的了,为了演示,我们将所有请求全部都负载到db2


定义SPI


我们从ShardingSphere的读写分离模块shardingspere-readwrite-spliltting-core中的META-INF/services下面看到了负载均衡的SPI。



org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.RoundRobinReplicaLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.RandomReplicaLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.WeightReplicaLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.FixedPrimaryLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.FixedReplicaRandomLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.FixedReplicaRoundRobinLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.FixedReplicaWeightLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.TransactionRandomReplicaLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.TransactionRoundRobinReplicaLoadBalanceAlgorithm
org.apache.shardingsphere.readwritesplitting.algorithm.loadbalance.TransactionWeightReplicaLoadBalanceAlgorithm


为了实现自己的负载均衡算法,我们需要在自己的模块中定义SPI,如下,在自己项目的META-INF/services目录下编写负载均衡SPI接口,里面内容为我们自定义的负载均衡算法的类文件的位置。



编写负载均衡算法核心代码


自定义负载均衡算法需要实现ReadQueryLoadBalanceAlgorithm接口,里面核心的两个方法是getDataSourcegetTypegetDataSource是算法的逻辑实现部分,其目的是选出一个目标数据库,此方法会传入readDataSourceNames,它是读库的集合,我们此处直接返回db2,那么会一直读db2getType是返回负载均衡算法的名称。


/**
 * 功能说明: 自定义负载均衡算法
 * <p>
 * Original @Author: steakliu-刘牌, 2022-07-20  18:05
 * <p>
 * Copyright (C)2020-2022  steakliu All rights reserved.
 */
public class CustomReplicaLoadBalanceAlgorithm implements ReadQueryLoadBalanceAlgorithm {
    @Getter
    private Properties props;
    @Override
    public String getDataSource(final String name, final String writeDataSourceName, final List<String> readDataSourceNames) {
        return "db2";
    }
    @Override
    public String getType() {
        return "CUSTOM";
    }
    @Override
    public void init(Properties props) {
        this.props = props;
    }
    @Override
    public boolean isDefault() {
        return false;
    }
}


在yml中使用自己实现的负载均衡算法


rules:
  sharding:
  readwrite-splitting:
    load-balancers:
      custom:
        type: CUSTOM
    data-sources:
      read_write_db:
        type: Static
        props:
          write-data-source-name: db1
          read-data-source-names: db2,db3,db4
        load-balancer-name: custom


发起大量的查询操作


从日志输出来看,所有的请求全部落在了db2上面,于是证明我们自定义的负载均衡算法成功了。



读写分离的中间件其实有很多,ShardingSphere旨在构建异构数据库上层的标准和生态,使用它我们基本上能解决数据库中的大部分问题,但是ShardingSphere也并不是万能的,还有一些东西没有实现,我们期待ShardingSphere能够实现更多强大,好用的功能。


关于ShardingSphere读写分离的分享,我们今天就先说到这里,后面我们会继续探索ShardingSphere的更多强大的功能,比如数据分片,高可用,数据加密,影子库等,今天的分享就到这里,感谢你的观看,我们下期见。



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
存储 SQL 关系型数据库
数据库魔法师:使用ShardingSphere实现MySQL读写分离与分片指南跟着爆叔的节奏稳了!
数据库魔法师:使用ShardingSphere实现MySQL读写分离与分片指南跟着爆叔的节奏稳了!
121 0
|
6月前
|
存储 中间件 关系型数据库
数据库切片大对决:ShardingSphere与Mycat技术解析
数据库切片大对决:ShardingSphere与Mycat技术解析
487 0
|
5月前
|
关系型数据库 MySQL 数据库
数据库读写分离后的数据同步方式
【6月更文挑战第5天】该文介绍了应对大并发请求的数据库解决方案,主要涉及MySQL的主从同步和读写分离。根据业务对数据一致性和延迟的容忍度选择合适模式,读写分离则能进一步优化数据库负载。
153 3
数据库读写分离后的数据同步方式
|
5月前
|
消息中间件 SQL 关系型数据库
数据库如何实现读写分离以应对高并发?
【6月更文挑战第17天】数据库如何实现读写分离以应对高并发?
75 1
|
6月前
|
SQL 存储 负载均衡
关系型数据库读写分离与主从复制
【5月更文挑战第2天】关系型数据库读写分离与主从复制
56 5
关系型数据库读写分离与主从复制
|
12月前
|
Java 关系型数据库 MySQL
数据库系列课程(04)-SpringBoot整合MySQL读写分离
数据库系列课程(04)-SpringBoot整合MySQL读写分离
109 0
|
12月前
|
SQL Oracle 关系型数据库
数据库系列课程(02)-MyCat读写分离
数据库系列课程(02)-MyCat读写分离
75 0
|
12月前
|
存储 Java 数据库连接
Spring Boot 配置主从数据库实现读写分离
Spring Boot 配置主从数据库实现读写分离
386 0
|
Cloud Native 关系型数据库 分布式数据库
阿里云最新产品手册——阿里云核心产品——云原生关系型数据库PolarDB——读写分离
阿里云最新产品手册——阿里云核心产品——云原生关系型数据库PolarDB——读写分离自制脑图
81 1
|
SQL 关系型数据库 MySQL
读写分离的数据库相连接步骤
读写分离的数据库相连接步骤
100 0
读写分离的数据库相连接步骤