Shardingsphere5分库分表

分库分表

垂直分库: 按业务拆**。**把不同的表放到不通的数据库中。

**水平分库:**同一张表拆成多个表,放到不同的库中(相同表结构的数据库就是水平分表)。

**水平分表:**一张表拆数据行(把一张表横着拆成多张,一般与水平分库一起用)。

**垂直分表:**把一张大表的列拆开。


分片 = 总称

分库 = 分片的一种(拆数据库)

分表 = 分片的一种(拆表)


水平分表(不与水平分库一起用)

bash 复制代码
db_order

├── t_order_0
├── t_order_1
├── t_order_2
├── t_order_3

水平分库与水平分表一起用

bash 复制代码
db_order_0

├── t_order_0
├── t_order_1


db_order_1

├── t_order_0
├── t_order_1

垂直分库 + 水平分库 + 水平分表(最典型)

bash 复制代码
db_user
t_user


对t_order进行水平分库和分表
db_order_0
t_order

db_order_1
t_order

只水平分库

bash 复制代码
db_order_0
t_order


db_order_1
t_order

分库分表的核心思想:数据分散存储,使得单一数据库/表的数据量变小来缓解单一数据库的性能问题,从而达到提升数据库性能的目的。


**垂直分库:**以表为依据,根据业务将不同表拆分到不同库中。

  1. 每个库的表结构都不一样。
  2. 每个库的数据也不一样。
  3. 所有库的并集是全量数据。

**垂直分表:**以字段为依据,根据字段属性将不同字段拆分到不同表中。

  1. 每个表的结构都不一样。
  2. 每个表的数据也不一样,一般通过一列(主键/外键)关联。
  3. 所有表的并集是全量数据。

**水平分库:**以字段为依据,按照一定策略,将一个库的数据拆分到多个库中。

  1. 每个库的表结构都一样。
  2. 每个库的数据都不一样。
  3. 所有库的并集是全量数据。

**水平分表:**以字段为依据,按照一定策略,将一个表的数据拆分到多个表中。

  1. 每个表的表结构都一样。
  2. 每个表的数据都不一样。
  3. 所有表的并集是全量数据。

配置环境

JDK8,SpringBoot(2.3.9.RELEASE),ShardingSphere-jdbc(5.1.1),MySQL8(一个主库,两个从库配置好主从复制)。

Maven依赖

XML 复制代码
<dependencies>

    <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.1.1</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

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

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

读写分离配置

参考文档:读写分离 :: ShardingSphere

ShardingSphere启动模式:

模式 作用
Memory 规则存在JVM内存
Standalone 单机持久化
Cluster 注册中心模式

负载均衡算法常用ROUND_ROBIN、RANDOM。

java 复制代码
spring:
  application:
    name: sharding-jdbc-dome
  profiles:
    active: dev
  shardingsphere:
    mode:
      type: Memory

    datasource:
      # 声明所有真实数据源的名称。
      #
      # 这里定义了3个真实数据库连接:
      # master:主库
      # slave1:第1个从库
      # slave2:第2个从库
      #
      # names中的名称必须与下面的数据源配置名称一致。
      # 名称不是固定的,也可以写成:
      # write-db,read-db-1,read-db-2
      names: master,slave1,slave2

      # 主库真实数据源配置。
      master:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33388/db_user
        username: root
        password: 123456

      # 第1个从库真实数据源配置。
      slave1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33307/db_user
        username: root
        password: 123456

      # 第2个从库真实数据源配置。
      slave2:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33308/db_user
        username: root
        password: 123456

    rules:
      # 读写分离规则。
      # ShardingSphere只负责SQL路由,不负责MySQL数据同步。
      # master到slave1、slave2的数据同步仍由MySQL主从复制完成。
      readwrite-splitting:
        data-sources:
          # 逻辑读写分离数据源名称。
          # myds不是一个真实MySQL数据库。
          # 它代表master、slave1、slave2组成的读写分离数据源组。
          # 名称可以自定义,例如:readwrite-ds,user-ds
          myds:
            # 读写分离类型。
            #
            # Static:静态读写分离。直接在配置文件中明确指定主库和从库。适用于固定的一主多从架构。
            # Dynamic:动态读写分离。与数据库发现规则配合使用,根据数据库集群状态动态识别主库和从库。不直接在这里固定写库和读库名称。
            #
            # 现在明确知道master、slave1、slave2,
            # 因此应该使用Static。
            type: Static

            props:
              # 写数据源名称。
              #
              # 必须引用datasource.names中已经声明的数据源。
              # INSERT、UPDATE、DELETE等写操作会路由到master。
              write-data-source-name: master

              # 读数据源名称列表。
              #
              # 多个从库之间使用英文逗号分隔。
              # 普通查询会按照负载均衡算法,
              # 在slave1和slave2之间选择。
              read-data-source-names: slave1,slave2

            # 当前读写分离数据源使用的负载均衡算法名称。
            #
            # alg_round是自定义名称,并不是固定值。
            # 必须与下面load-balancers中的名称保持一致。
            load-balancer-name: alg_round

        load-balancers:
          # 负载均衡算法实例名称。
          #
          # alg_round可以任意命名,例如:
          # round-robin-algorithm,read-random
          # 只要与上面的load-balancer-name保持一致即可。
          alg_round:
            # 从库负载均衡算法类型。
            # ROUND_ROBIN:轮询。
            # RANDOM:随机。
            # WEIGHT:权重。
            type: ROUND_ROBIN

    props:
      # 是否输出ShardingSphere的SQL解析和路由日志,可选值:
      # true:输出逻辑SQL、实际SQL以及实际访问的数据源。
      # false:不输出相关SQL路由日志。
      sql-show: true

下面是权重类型的写法,其它的不变,Double越大,权重越大。

bash 复制代码
            load-balancer-name: olg_weight
        load-balancers:
          olg_weight:
            type: WEIGHT
            props:
              slave1: 1.0
              slave2: 2.0

如果在同一个事务下,有增删改也有查询,只会查询主数据库,而不是从数据库。

java 复制代码
@Transactional
@Test
void transactionTest(){
    User user = new User();
    user.setUname("张三丰");
    userMapper.insert(user);

    List<User> users = userMapper.selectList(null);
    System.out.println(users);
}

垂直分库+水平分库+水平分表 配置

环境说明

  • 一个逻辑表:t_order

  • 两个真实数据库:

    • server-order0 → MySQL数据库 db_order

    • server-order1 → MySQL数据库 db_order

  • 每个数据库两个真实表:

    • t_order0

    • t_order1

最终形成:2个库 × 2张表 = 4张真实订单表,对应的配置如下:

bash 复制代码
t_order:
 actual-data-nodes:
 server-order$->{0..1}.t_order$->{0..1}

分库规则

bash 复制代码
database-strategy:
 standard:
  sharding-column: user_id
  sharding-algorithm-name: alg_mod

配置说明根据:user_id,决定数据库算法:偶数用户:server-order0,奇数用户:server-order1

bash 复制代码
alg_mod:
  type: MOD
  props:
    sharding-count: 2 # 针对sharding-column: user_id字段,对2取模
user_id 计算 数据库
1 1%2=1 server-order1
2 2%2=0 server-order0
3 3%2=1 server-order1
4 4%2=0 server-order0

分表规则

复制代码
table-strategy:
 standard:
  sharding-column: order_no
  sharding-algorithm-name: alg_hash_mod

表示同一个数据库里面,再根据:order_no,决定放到哪个表中。

bash 复制代码
alg_hash_mod:
  type: HASH_MOD
  props:
    sharding-count: 2 # 针对sharding-column: user_id字段,对2取模

例如:订单号:hash(10001)%2=0 进入t_order0,另一个:hash(10002)%2=1 进入:t_order1。

雪花ID

id字段自动生成,id字段要配合mybatis-plus的"@TableId(type = IdType.AUTO)"。

XML 复制代码
t_order:
  key-generate-strategy:
    column:id
    key-generator-name:alg_snowflake

完整配置文件

XML 复制代码
spring:
  application:
    name: sharding-jdbc-dome
  profiles:
    active: dev
  shardingsphere:
    mode:
      type: Memory
    datasource:
      names: server-user,server-order0,server-order1
      server-user:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33008/db_user?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      server-order0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33016/db_order?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      server-order1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33017/db_order?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
    props:
      sql-show: true
    rules:
      sharding:
        tables:
          t_user:
            actual-data-nodes: server-user.t_user
          t_order:
            actual-data-nodes: server-order$->{0..1}.t_order$->{0..1}
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: alg_mod
            table-strategy:
              standard:
                sharding-column: order_no
                sharding-algorithm-name: alg_hash_mod
            key-generate-strategy:
              column: id
              key-generator-name: alg_snowflake
        sharding-algorithms:
          alg_inline_userId:
            type: INLINE
            props:
              algorithm-expression: server-order$->{user_id % 2}
          alg_mod:
            type: MOD
            props:
              sharding-count: 2 # 针对sharding-column: user_id字段,对2取模
          alg_hash_mod:
            type: HASH_MOD
            props:
              sharding-count: 2 # 针对sharding-column: user_id字段,对2取模
        key-generators:
          alg_snowflake:
            type: SNOWFLAKE

读写分离

环境说明

  • 一个主库(master)负责写
  • 两个从库(slave1、slave2)负责读
  • 查询自动分发到从库
  • 插入、更新、删除自动走主库

注意:如果是在一个事务中进行了增删改,之后并执行了查询,那么此时为了保证数据一致性,此时会自动查询主库。

配置读写分离规则

XML 复制代码
rules:
  readwrite-splitting:

创建一个逻辑数据源

myds对应的是:"master slave1 slave2"三个数据源。

XML 复制代码
data-sources:
  myds:

手动指定读写库

XML 复制代码
myds:
  type: Static
  props:
    write-data-source-name: master
    read-data-source-names: slave1,slave2

负载均衡配置

XML 复制代码
load-balancers:
  alg_round:
    type: ROUND_ROBIN
  # 轮训或者按权重
  olg_weight:
    type: WEIGHT
    props:
      slave1: 1.0
      slave2: 2.0

完整配置文件

XML 复制代码
spring:
  application:
    name: sharding-jdbc-dome
  profiles:
    active: dev
  shardingsphere:
    mode:
      type: Memory
    datasource:
      names: master,slave1,slave2
      master:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33388/db_user
        username: root
        password: 123456
      slave1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33307/db_user
        username: root
        password: 123456
      slave2:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33308/db_user
        username: root
        password: 123456
    rules:
      readwrite-splitting:
        data-sources:
          myds:
            type: Static
            props:
              write-data-source-name: master
              read-data-source-names: slave1,slave2
            load-balancer-name: olg_weight
        load-balancers:
          alg_round:
            type: ROUND_ROBIN
          olg_weight:
            type: WEIGHT
            props:
              slave1: 1.0
              slave2: 2.0
    props:
      sql-show: true

绑定表

环境说明

订单系统这种"一张主表 + 多张关联子表",并且数据量很大,需要分库分表的场景。

适用于order和order_item这种同一个订单的数据、生命周期一致的表,保证在分库分表的情况下,order和order_item在同一个数据库中,而不是分散在不同的数据库中,避免跨库关联查询,提高关联查询效率。

使用场景

这个配置是在前面的水平分库分表 基础上,又增加了一个非常重要的概念:绑定表。经常一起JOIN,并且分片规则完全一样的表。

**解决:**分库分表之后,多表关联查询如何避免产生大量无效查询(笛卡尔积)。

XML 复制代码
                    SpringBoot应用
                         |
                 ShardingSphere-JDBC
                         |
        ---------------------------------
        |                               |
    server-order0                  server-order1
        |                               |
 t_order0                       t_order0
 t_order1                       t_order1

 t_order_item0                  t_order_item0
 t_order_item1                  t_order_item1

ShardingSphere的绑定表支持多个表组成一组,也支持配置多个绑定表组

使用前提:多个表的分库分表规则必须完全一致。

SQL联查绑定表关联时,最好使用**分片键(**例如:order_no)进行关联。

sql 复制代码
SELECT o.order_no, SUM(i.price * i.count) AS amount
FROM t_order o
JOIN t_order_item i ON o.order_no = i.order_no
GROUP BY o.order_no;

完整配置文件

复制代码
spring:
  application:
    name: sharding-jdbc-dome
  profiles:
    active: dev
  shardingsphere:
    mode:
      type: Memory
    datasource:
      names: server-user,server-order0,server-order1
      server-user:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33008/db_user?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      server-order0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33016/db_order?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      server-order1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33017/db_order?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
    props:
      sql-show: true
    rules:
      sharding:
        tables:
          t_user:
            actual-data-nodes: server-user.t_user
          t_order:
            actual-data-nodes: server-order$->{0..1}.t_order$->{0..1}
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: alg_mod
            table-strategy:
              standard:
                sharding-column: order_no
                sharding-algorithm-name: alg_hash_mod
            key-generate-strategy:
              column: id
              key-generator-name: alg_snowflake
          t_order_item:
            actual-data-nodes: server-order$->{0..1}.t_order_item$->{0..1}
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: alg_mod
            table-strategy:
              standard:
                sharding-column: order_no
                sharding-algorithm-name: alg_hash_mod
            key-generate-strategy:
              column: id
              key-generator-name: alg_snowflake
        sharding-algorithms:
          alg_inline_userId:
            type: INLINE
            props:
              algorithm-expression: server-order$->{user_id % 2}
          alg_mod:
            type: MOD
            props:
              sharding-count: 2 # 针对sharding-column: user_id字段,对2取模
          alg_hash_mod:
            type: HASH_MOD
            props:
              sharding-count: 2 # 针对sharding-column: user_id字段,对2取模
        key-generators:
          alg_snowflake:
            type: SNOWFLAKE
        # 绑定表:指分片规则一致的一组分片表。 使用绑定表进行多表关联查询时,必须使用分片键进行关联,
        #       否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。
        binding-tables[0]: t_order,t_order_item # 去掉笛卡尔积的关联

广播表

指所有的分片数据源中都存在的表,表结构及其数据在每个数据库中均完全一致。 适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表,商品分类表。订单状态表。

广播具有以下特性:

(1)插入、更新操作会实时在所有节点上执行,保持各个分片的数据一致性

(2)查询操作,只从一个节点获取

(3)可以跟任何一个表进行 JOIN 操作

环境说明:

  • 需要提前在这3个数据库中创建结构完全相同的t_dict表:
  • 逻辑表 t_dict 对应3张真实表:
  • server-user对应的db_user.t_dict
  • server-order0对应的db_order.t_dict
  • server-order1对应的db_order.t_dict

核心配置

逻辑表 t_dict 对应3张真实表:

复制代码
t_dict:
  actual-data-nodes: server-order$->{0..1}.t_dict,server-user.t_dict

broadcast-tables[0]: t_dict

完整配置文件

复制代码
spring:
  application:
    name: sharding-jdbc-dome
  profiles:
    active: dev
  shardingsphere:
    mode:
      type: Memory
    datasource:
      names: server-user,server-order0,server-order1
      server-user:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33008/db_user?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      server-order0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33016/db_order?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      server-order1:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        jdbc-url: jdbc:mysql://127.0.0.1:33017/db_order?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
    props:
      sql-show: true
    rules:
      sharding:
        tables:
          t_user:
            actual-data-nodes: server-user.t_user
          t_order:
            actual-data-nodes: server-order$->{0..1}.t_order$->{0..1}
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: alg_mod
            table-strategy:
              standard:
                sharding-column: order_no
                sharding-algorithm-name: alg_hash_mod
            key-generate-strategy:
              column: id
              key-generator-name: alg_snowflake
          t_order_item:
            actual-data-nodes: server-order$->{0..1}.t_order_item$->{0..1}
            database-strategy:
              standard:
                sharding-column: user_id
                sharding-algorithm-name: alg_mod
            table-strategy:
              standard:
                sharding-column: order_no
                sharding-algorithm-name: alg_hash_mod
            key-generate-strategy:
              column: id
              key-generator-name: alg_snowflake
          t_dict:
            actual-data-nodes: server-order$->{0..1}.t_dict,server-user.t_dict
        sharding-algorithms:
          alg_inline_userId:
            type: INLINE
            props:
              algorithm-expression: server-order$->{user_id % 2}
          alg_mod:
            type: MOD
            props:
              sharding-count: 2 # 针对sharding-column: user_id字段,对2取模
          alg_hash_mod:
            type: HASH_MOD
            props:
              sharding-count: 2 # 针对sharding-column: user_id字段,对2取模
        key-generators:
          alg_snowflake:
            type: SNOWFLAKE
        # 绑定表:指分片规则一致的一组分片表。 使用绑定表进行多表关联查询时,必须使用分片键进行关联,
        #       否则会出现笛卡尔积关联或跨库关联,从而影响查询效率。
        binding-tables[0]: t_order,t_order_item # 去掉笛卡尔积的关联
        broadcast-tables[0]: t_dict
相关推荐
wWYy.2 小时前
Mysql:主键索引 唯一索引 普通索引 前缀索引
数据库·mysql
宝杰X72 小时前
Android Room3 多平台数据库
android·数据库
sky_8106135 小时前
Oracle ERP 各模块业务管理功能及底层表说明
数据库·oracle
YMatrix 官方技术社区7 小时前
CittaBase vs. Neo4j :原生图性能实测与混合检索实践
数据库·功能测试·ymatrix
闲猫8 小时前
LangChain / Integrations / Integrations by component / Tool
java·数据库·langchain
xqqxqxxq8 小时前
SQL 连接查询技术笔记
数据库·笔记·sql
在世修行8 小时前
Windows 上 Docker Desktop 部署 MySQL + TDengine 全过程(含 WSL 报错与镜像加速排障实战)
windows·mysql·docker·tdengine
Databend8 小时前
从万亿级大模型到全线应用:Databend Cloud 助力头部 AI 企业构建全链路 Trace 数据管道
大数据·数据库·sql
MC皮蛋侠客8 小时前
SQLAlchemy 系列(十一):从 1.x 到 2.x——渐进迁移与数据访问层治理
数据库·python