Spring Boot集成ShardingSphere实现读写分离(四) | Spring Cloud 43

news2024/11/18 9:23:29

一、读写分离

1.1 背景

面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。

通过一主多从的配置方式,可以将查询请求均匀的分散到多个数据副本,能够进一步的提升系统的处理能力。 使用多主多从的方式,不但能够提升系统的吞吐量,还能够提升系统的可用性,可以达到在任何一个数据库宕机,甚至磁盘物理损坏的情况下仍然不影响系统的正常运行。

与将数据根据分片键打散至各个数据节点的水平分片不同,读写分离则是根据 SQL 语义的分析,将读操作和写操作分别路由至主库与从库。

在这里插入图片描述
读写分离的数据节点中的数据内容是一致的,而水平分片的每个数据节点的数据内容却并不相同。将水平分片和读写分离联合使用,能够更加有效的提升系统性能。

1.2 挑战

读写分离虽然可以提升系统的吞吐量和可用性,但同时也带来了数据不一致的问题。 这包括多个主库之间的数据一致性,以及主库与从库之间的数据一致性的问题。 并且,读写分离也带来了与数据分片同样的问题,它同样会使得应用开发和运维人员对数据库的操作和运维变得更加复杂。 下图展现了将数据分片与读写分离一同使用时,应用程序与数据库集群之间的复杂拓扑关系。
在这里插入图片描述

1.3 应用场景

许多系统通过采用主从数据库架构的配置来提高整个系统的吞吐量,但是主从的配置也给业务的使用带来了一定的复杂性。接入 ShardingSphere,可以利用读写分离功能管理主从数据库,实现透明化的读写分离功能,让用户像使用一个数据库一样使用主从架构的数据库。

不足之处:

  • ShardingSphere实现读写分离不支持多主库数据分片,支持单主库多表数据分片
  • ShardingSphere实现读写分离需自定实现主从数据库的同步

二、Mysql主从数据库同步

请见往期章节:Mysql8 数据库安装及主从配置 | Spring Cloud 2

三、读写分离示例示例

3.1 读写分开总体结构

3.1.1 主库数据源write_ds1

数据库地址数据源名称真实表名逻辑表名称业务描述
192.168.0.35write_ds1t_goods_0t_goods商品表-分表
192.168.0.35write_ds1t_goods_1t_goods商品表-分表

3.1.2 从库数据源read_ds1

数据库地址数据源名称真实表名逻辑表名称业务描述
192.168.0.45read_ds1t_goods_0t_goods商品表-分表
192.168.0.45read_ds1t_goods_1t_goods商品表-分表

3.1.3 从库数据源read_ds2

数据库地址数据源名称真实表名逻辑表名称业务描述
192.168.0.46read_ds2t_goods_0t_goods商品表-分表
192.168.0.46read_ds1t_goods_1t_goods商品表-分表

3.1.1 逻辑商品表 t_goods

-- ----------------------------
-- Table structure for t_goods_0
-- ----------------------------
DROP TABLE IF EXISTS `t_goods_0`;
CREATE TABLE `t_goods_0`  (
  `goods_id` bigint NOT NULL,
  `goods_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '商品名称',
  `main_class` bigint NULL DEFAULT NULL COMMENT '商品大类数据字典',
  `sub_class` bigint NULL DEFAULT NULL COMMENT '商品小类数据字典',
  PRIMARY KEY (`goods_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Table structure for t_goods_1
-- ----------------------------
DROP TABLE IF EXISTS `t_goods_1`;
CREATE TABLE `t_goods_1`  (
  `goods_id` bigint NOT NULL,
  `goods_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '商品名称',
  `main_class` bigint NULL DEFAULT NULL COMMENT '商品大类数据字典',
  `sub_class` bigint NULL DEFAULT NULL COMMENT '商品小类数据字典',
  PRIMARY KEY (`goods_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

3.2 项目结构

3.2.1 项目总体结构

在这里插入图片描述

3.2.2 Maven 依赖

shading-sphere/shading-readwrite/pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>shading-sphere</artifactId>
        <groupId>com.gm</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shading-readwrite</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.3.1</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>


        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.33</version>
        </dependency>

    </dependencies>

</project>
  • shardingsphere-jdbc-core-spring-boot-starter使用版本5.2.1

  • JDBCORM 框架选用mybatis-plus

3.2.3 配置文件

server:
  port: 8844

spring:
  application:
    name: @artifactId@
  shardingsphere:
    # 数据源配置
    datasource:
      names: write_ds1,read_ds1,read_ds2
      write_ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.0.35:3306/db1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: '1qaz@WSX'
      read_ds1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.0.45:3306/db1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: '1qaz@WSX'
      read_ds2:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.0.46:3306/db1?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&allowMultiQueries=true&serverTimezone=Asia/Shanghai
        username: root
        password: '1qaz@WSX'
    # 定义规则
    rules:
      sharding:
        # 数据分片规则配置
        tables:
          # 指定某个表的分片配置,逻辑表名
          t_goods:
            # 这个配置是告诉sharding有多少个库和多少个表及所在实际的数据库节点,由数据源名 + 表名组成(参考 Inline 语法规则)
            actual-data-nodes: readwrite_ds.t_goods_$->{0..1} # 此处使用下方定义的读写分离数据源
            # 配置表分片策略
            table-strategy:
              # 用于单分片键的标准分片场景
              standard:
                # 分片列名称
                sharding-column: main_class
                # 分片算法名称
                sharding-algorithm-name: t_goods_table_inline
            # 分布式序列策略
            key-generate-strategy:
              # 自增列名称,缺省表示不使用自增主键生成器
              column: goods_id
              # 分布式序列算法名称
              key-generator-name: snowflake
        # 分片算法配置
        sharding-algorithms:
          # 分片算法名称
          t_goods_table_inline:
            # 分片算法类型
            type: INLINE
            # 分片算法属性配置
            props:
              algorithm-expression: t_goods_${main_class % 2}
        # 分布式序列算法配置(如果是自动生成的,在插入数据的sql中就不要传id,null也不行,直接插入字段中就不要有主键的字段)
        keyGenerators:
          # 分布式序列算法名称
          snowflake:
            # 分布式序列算法类型
            type: SNOWFLAKE
      readwrite-splitting:
        dataSources:
          readwrite_ds: # 此处定义的数据源名称在上分分表中使用
            staticStrategy:
              writeDataSourceName: write_ds1
              readDataSourceNames:
                - read_ds1
                - read_ds2
            # dynamicStrategy:
            loadBalancerName: myBalancer
        load-balancers:
          myBalancer:
            type: RANDOM
            props:
              transactionalReadQueryStrategy: PRIMARY
    props:
      sql-show: true #显示sql

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

配置简要说明:

商品逻辑表t_goods

  • 按照商品大类取模分片算法进行分表

读写分离规则中定义的数据源名称readwrite_ds,在逻辑表t_goods的数据分片规则中得用应用(actual-data-nodes属性)

3.2.4 实体定义

com/gm/shading/readwrite/entity/Goods.java

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("t_goods")
public class Goods {

    @TableId(type = IdType.ASSIGN_ID)
    private Long goodsId;

    private String goodsName;

    private Long mainClass;

    private Long subClass;

}

3.2.5 定义mapper

com/gm/shading/readwrite/mapper/GoodsMapper.java

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.gm.shading.readwrite.entity.Goods;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface GoodsMapper extends BaseMapper<Goods> {
    void save(Goods goods);
}

src/main/resources/mapper/GoodsMapper.xml

<?xml version="1.0" encoding="UTF-8"?>

<!--
  ~ Copyright (c) 2020 mttsmart4cloud Authors. All Rights Reserved.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.gm.shading.readwrite.mapper.GoodsMapper">
    <insert id="save" parameterType="com.gm.shading.readwrite.entity.Goods">
        insert into t_goods (goods_name, main_class, sub_class)
        values (#{goodsName}, #{mainClass}, #{subClass})
    </insert>
</mapper>

3.2.6 单元测试

src/test/java/com/gm/shading/readwrite/ShadingReadWriteApplicationTests.java

package com.gm.shading.readwrite;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gm.shading.readwrite.entity.Goods;
import com.gm.shading.readwrite.mapper.GoodsMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Random;

@SpringBootTest
public class ShadingReadWriteApplicationTests {

    @Autowired
    GoodsMapper goodsMapper;

    // 分布式队列不生效,使用数据库递增
    @Test
    void addGoods() throws InterruptedException {
        for (int i = 1; i <= 10; i++) {
            Goods goods = new Goods();

            Random random = new Random();
            int mainClass = random.nextInt(100) + 1;
            int subClass = random.nextInt(100) + 1;
            goods.setMainClass((long) mainClass);
            goods.setSubClass((long) subClass);
            goods.setGoodsName("商品" + i);
            goodsMapper.insert(goods);
        }

        Thread.sleep(2000);
        for (int i = 1; i <= 10; i++) {
            QueryWrapper<Goods> queryWrapper = new QueryWrapper<>();
            List<Goods> list = goodsMapper.selectList(queryWrapper.orderByAsc("goods_id"));
            for (Goods goods : list) {
                System.out.println(goods.toString());
            }
        }
    }

    // 分布式队列生效,使用雪花算法生成ID
    @Test
    void addGoods2() throws InterruptedException {
        for (int i = 1; i <= 10; i++) {
            Goods goods = new Goods();

            Random random = new Random();
            int mainClass = random.nextInt(100) + 1;
            int subClass = random.nextInt(100) + 1;
            goods.setMainClass((long) mainClass);
            goods.setSubClass((long) subClass);
            goods.setGoodsName("商品" + i);
            goodsMapper.save(goods);
        }

        Thread.sleep(2000);
        for (int i = 1; i <= 10; i++) {
            QueryWrapper<Goods> queryWrapper = new QueryWrapper<>();
            List<Goods> list = goodsMapper.selectList(queryWrapper.orderByAsc("goods_id"));
            for (Goods goods : list) {
                System.out.println(goods.toString());
            }
        }
    }
}

3.2.7 数据分片及读写分离效果

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/496393.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt的Model/View结构

Model/View结构 将界面组件与所编辑的数据分离开来&#xff0c;又通过数据源的方式连接起来&#xff0c;是处理界面与数据的一种较好的方式。Qt使用Model/View结构来处理这种关系&#xff0c;Model/View的基本结构如图5-1所示。其中各部分的功能如下。 图1 Model/View基本结构…

ps磨皮插件专用智能磨皮插件 AI算法美颜 提高P图效率

ps的功能这么强大&#xff0c;其美白磨皮方法当然不止一种。本文就给大家细数一下ps美白磨皮常用的几种方法。在各种方法中&#xff0c;插件法的操作更为简单&#xff0c;效果也更好&#xff0c;因此我们还会介绍ps磨皮美白插件哪个好。事不宜迟&#xff0c;一起来看看吧。 一…

Throwable、Error、Exception 运行时异常、非运行时异常

一、Throwable Throwable类&#xff08;可抛出&#xff09;是一个超类&#xff0c;是所有错误和异常根。只有继承于Throwable的类或者其子类才能够被抛出。 有两个子类为Error和Exception&#xff0c;其他的异常类都继承于这两个子类。 三、Error和Exception Error类及其子类…

C++知识点 -- 智能指针

C知识点 – 智能指针 文章目录 C知识点 -- 智能指针一、智能指针的使用及原理1.使用场景2.RAII3.智能指针的设计思想4.智能指针的拷贝问题 二、auto_ptr三、unique_ptr四、shared_ptr1.模拟实现2.shared_ptr的循环引用 五、weak_ptr六、定制删除器七、内存泄漏1.什么是内存泄漏…

PDF转Word免费的软件有哪些?(完整教程版!)

这五种免费PDF转Word的方式&#xff0c;不仅免费&#xff0c;还能准确恢复PDF文件内容&#xff0c;前方高能&#xff0c;快速学习&#xff01; 1.Office直接打开 大厂软件&#xff0c;既能读文档又能转换格式&#xff0c;总让人放心。 转换流程1&#xff1a;在Word的最新版本…

Zero系列三部曲:Zero、Zero-Offload、Zero-Infinity

Zero系列三部曲&#xff1a;Zero、Zero-Offload、Zero-Infinity ZeroIntroductionZero DP流程图详解 Zero-R Zero-OffloadZero- Infinityreference Zero Introduction 以数据并行为例&#xff0c;在训练的时候&#xff0c;首先把模型参数在每个GPU上复制一份&#xff0c;然后…

IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)

一、OSI模型与TCP/IP协议栈 1.1 OSI 7层模型&#xff1a; 应用层&#xff1a; 功能&#xff1a;用户接口&#xff0c;文件传输、电子邮件、虚拟终端、文件服务 设备&#xff1a;网关 协议&#xff1a;HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet 表示层&#xff1a; 功能&…

Spring 面试题总结(2023最新版)

文章目录 1、谈谈你对Spring的理解&#xff1f;1.1 发展历程1.2 Spirng的组成1.3 Spring的好处 2、Autowired和Resource的区别2.1 共同点&#xff1a;2.2 Autowired2.3 Resource2.3.1 Resource的装配顺序 3、Spring常用注解3.1、给容器中注入组件3.1.1 包扫描组件标注注解3.1.2…

复数的基本知识

复数的基本知识 文章目录 复数的基本知识前言表示方法百度百科简单来说&#xff1a; 复数的运算 前言 这里只有一点点关于复数的知识&#xff0c;主要是最近的FFT要用到。 表示方法 百度百科 我们把形如 abi &#xff08;a,b均为实数&#xff09;的数称为复数&#xff0c;其…

c++ “拷贝构造,运算符重载”

1.拷贝构造 拷贝构造的意思为&#xff1a;创造一个对象并拷贝另一个对象. 拷贝构造的名字与类的名字一致&#xff0c;参数一般为引用&#xff0c;若类中为无拷贝构造&#xff0c;编译器会自动生成默认拷贝构造函数&#xff0c;这种默认的拷贝构造函数只能拷贝内容&#xff0c;不…

安装并使用JupyterLab

背景 JupyterLab 是用于笔记本、代码和数据的最新的基于 Web 的交互式开发环境。其灵活的界面允许用户配置和安排数据科学、科学计算、机器学习方面的工作流程。模块化设计邀请扩展来扩展和丰富功能。 部署 要在本机搭建 Jupyter Notebook 平台进行机器学习项目&#xff0c;…

【Python入门篇】——Python基础语法(字符串扩展和格式化的精度控制)

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; Python入门&#xff0c;本专栏主要内容为Python的基础语法&#xff0c;Python中的选择循环语句…

网络安全之IPSEC路由基本配置

目录 网络安全之IPSEC路由基本配置 IPSEC配置的前提分析 协议分析 传输模式分析​编辑 IPSEC路由中的配置 图谱图 配置公网可达 R1配置IKE SA的安全提议 R1配置 IKE SA 的身份认证信息 R3配置IKE SA的安全提议 R3配置 IKE SA 的身份认证信息 R1配置IPSEC的安全提议…

112-Linux_mysql数据库的安装

文章目录 一.数据库介绍1.数据库2.数据库的分类 二.mysql安装及设置1.安装mysql2.初始化配置(1)设置数据库不进行密码强校验(2)设置root管理员密码(3)设置是否要删除匿名用户&#xff0c;这里不删除(4)设置是否允许root用户远程登录&#xff0c;这里设置允许(5)是否删除test库&…

硬件设计 之 PCIe常用知识

以下是本人在自己在设计PCIe中常遇到的一些知识&#xff0c;对他们进行了简单整理一下&#xff0c;包括基本定义、传输速率、layout要求等。比如作为硬件工程师要了解芯片架构&#xff0c;哪些PCIe接口可以使用&#xff0c;使用这些PCIe要做什么&#xff0c;需要使用PCIe x1还是…

msvc编译opencascade和vtk

文章目录 msvc编译opencascade和vtk下载源码和第三方库开始编译VTK开始编译OCC msvc编译opencascade和vtk 下载源码和第三方库 opencascade源码 我下载的时候最新版本是7.7.0 第三方库文件 这里面标出来的是必须的文件&#xff0c;如果你需要别的&#xff0c;也可以下载其他的…

JNI开发

文件结构&#xff08;选中的为生成的&#xff09; CMake构建不需要执行命令&#xff0c;会自动生成so文件打包进apk Android mk构建需要执行命令生成so文件&#xff0c;再打包进apk。命令如下。 # 在jni目录下执行 # 生成com_demo_cppproject_OtherNdkTest.h头文件 javac -h .…

[MySQL / Mariadb] 数据库学习-Linux中二进制方式安装MySQL5.7

Linux中二进制方式安装MySQL5.7 安装安装方式官网下载安装包创建用户组mysql&#xff0c;用户和目录把下载的安装包&#xff0c;放到/home/mysql/将本地文件拷贝到远程&#xff1a; scp 文件名 –用户名计算机IP或者计算机名称:远程路径 验证包解压安装包&#xff0c;移动到/us…

【前端面试题】深拷贝的终极实现

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 引子 通过本文可以学习到深拷贝的三种写法的实现思路与性能差异 首先&#xff0c;我们要理…

Hystrix 简单聊聊断路器/熔断器

本文首发自「慕课网」&#xff0c;想了解更多IT干货内容&#xff0c;程序员圈内热闻&#xff0c;欢迎关注"慕课网"&#xff01; 作者&#xff1a;风间影月|慕课网讲师 什么是Hystrix Hystrix 在SpringCloud中负责服务熔断服务降级的作用。 Hystrix 存在的目的也是…