大厂都在用的分库分表 12 种分片算法

超大数据量存储常用数据库分表分库算法总结 主要介绍了超大数据量存储常用数据库分表分库算法总结,本文讲解了按自然时间来分表/分库、按数字类型hash分表/分库、按md5值来分表/分库三种方法,以及分表所带来的问题探讨,需要的朋友可以参考下 立即下载

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 

8a680d0d4c4328b4047d3c688a687f1e.gif

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号、CRM 等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本 

来源:程序员小富


前言

我们一起梳理下ShardingSphere框架中的核心部分分片策略 和分片算法 ,其内部针为我们提供了多种分片策略和分片算法,来应对不同的业务场景,本着拿来即用的原则。

这次将详细介绍如何在ShardingSphere-jdbc中实战 5 种分片策略和 12 种分片算法,自定义分片算法,比较它们的应用场景以及优劣。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

分片策略

分片策略是分片键和分片算法的组合策略,真正用于实现数据分片操作的是分片键与相应的分片算法。在分片策略中,分片键确定了数据的拆分依据,分片算法则决定了如何对分片键值运算,将数据路由到哪个物理分片中。

由于分片算法的独立性,使得分片策略具有更大的灵活性和可扩展性。这意味着可以根据具体需求选择不同的分片算法,或者开发自定义的分片算法,以适应各种不同的分片场景。在分表和分库时使用分片策略和分片算法的方式是一致的 。

注意 :如果在某种分片策略中使用了不受支持的SQL操作符,比如 MYSQL 某些函数等,那么系统将无视分片策略,进行全库表路由操作。这个在使用时要慎重!

ShardingSphere对外提供了standard、complex、hint、inline、none5种分片策略。不同的分片策略可以搭配使用不同的分片算法,这样可以灵活的应对复杂业务场景。

标准分片策略

标准分片策略(standard)适用于具有单一分片键 的标准分片场景。该策略支持精确分片,即在SQL中包含=、in操作符,以及范围分片,包括BETWEEN AND、>、<、>=、<=等范围操作符。

该策略下有两个属性,分片字段shardingColumn和分片算法名shardingAlgorithmName。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 逻辑表名称
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分库策略
            databaseStrategy: # 分库策略
              standard: # 用于单分片键的标准分片场景
                shardingColumn: order_id # 分片列名称
                shardingAlgorithmName: # 分片算法名称
           tableStrategy: # 分表策略,同分库策略

行表达式分片策略

行表达式分片策略(inline)适用于具有单一分片键 的简单分片场景,支持SQL语句中=和in操作符。

它的配置相当简洁,该分片策略支持在配置属性algorithm-expression中书写Groovy表达式,用来定义对分片健的运算逻辑,无需单独定义分片算法了。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 逻辑表名称
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分库策略
            databaseStrategy: # 分库策略
              inline:   # 行表达式类型分片策略
                algorithm-expression: db$->{order_id % 2} Groovy表达式
            tableStrategy: # 分表策略,同分库策略

复合分片策略

复合分片策略(complex)适用于多个分片键 的复杂分片场景,属性shardingColumns中多个分片健以逗号分隔。支持 SQL 语句中有>、>=、<=、<、=、IN 和 BETWEEN AND 等操作符。

比如:我们希望通过user_id和order_id等多个字段共同运算得出数据路由到具体哪个分片中,就可以应用该策略。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 逻辑表名称
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分库策略
            databaseStrategy: # 分库策略
              complex: # 用于多分片键的复合分片场景
                shardingColumns: order_id,user_id # 分片列名称,多个列以逗号分隔
                shardingAlgorithmName: # 分片算法名称
            tableStrategy: # 分表策略,同分库策略

Hint分片策略

Hint强制分片策略相比于其他几种分片策略稍有不同,该策略无需配置分片健,由外部指定分库和分表的信息,可以让SQL在指定的分库、分表中执行。

使用场景:

  • 分片字段不存在SQL和数据库表结构中,而存在于外部业务逻辑。

  • 强制在指定数据库进行某些数据操作。

比如,我们希望用user_id做分片健进行路由订单数据,但是t_order表中也没user_id这个字段啊,这时可以通过Hint API手动指定分片库、表等信息,强制让数据插入指定的位置。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 逻辑表名称
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分库策略
            databaseStrategy: # 分库策略
              hint: # Hint 分片策略
                shardingAlgorithmName: # 分片算法名称
            tableStrategy: # 分表策略,同分库策略

不分片策略

不分片策略比较好理解,设置了不分片策略,那么对逻辑表的所有操作将会执行全库表路由。

spring:
  shardingsphere:
    rules:
      sharding:
        tables:
          t_order: # 逻辑表名称
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${1..10}
            # 分库策略
            databaseStrategy: # 分库策略
              none: # 不分片
           tableStrategy: # 分表策略,同分库策略

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

分片算法

ShardingSphere 内置了多种分片算法,按照类型可以划分为自动分片算法、标准分片算法、复合分片算法和 Hint 分片算法,能够满足我们绝大多数业务场景的需求。

此外,考虑到业务场景的复杂性,内置算法也提供了自定义分片算法的方式,我们可以通过编写 Java代码来完成复杂的分片逻辑。下边逐个算法实践一下,看看每种算法的实际执行效果。

开始前,我要吐槽下官方文档,对于算法这种至关重要的内容,解释描述的过于潦草,对于新手入门不友好,学习成本偏高啊

准备工作

给逻辑表配置完算法后,先执行创建表的SQL,这样就可以依据你的算法在db内快速生成分片表。

自动分片算法

1、MOD

取模分片算法是内置的一种比较简单的算法,定义算法时类型MOD,表达式大致(分片健/数据库实例) % sharding-count,它只有一个 props 属性sharding-count代表分片表的数量。

82fe58afe05869096fc505448a67ab62.png

这个 sharding-count 数量使用时有点小坑,比如db0和db1都有分片表t_order_1,那么实际上数量只能算一个。YML核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 自动分片表规则配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_mod
        # 分片算法定义
        sharding-algorithms:
          t_order_table_mod:
            type: MOD # 取模分片算法
            props:
              # 指定分片数量
              sharding-count: 6
        tables:
          t_order: # 逻辑表名称
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
            ....
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_mod
2、HASH_MOD

哈希取模分片算法是内置取模分片算法的一个升级版本,定义算法时类型HASH_MOD,也只有一个props属性sharding-count代表分片的数量。表达式hash(分片健/数据库实例) % sharding-count。

66b0ee3dfcbf558a9ca1d36b3565d794.png

YML核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 自动分片表规则配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_hash_mod
        # 分片算法定义
        sharding-algorithms:
          t_order_table_hash_mod:
            type: HASH_MOD # 哈希取模分片算法
            props:
              # 指定分片数量
              sharding-count: 6
        tables:
          t_order: # 逻辑表名称
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
            ....
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_hash_mod
3、VOLUME_RANGE

基于分片容量的范围分片算法,依据数据容量来均匀分布到分片表中。

它适用于数据增长趋势相对均匀,按分片容量将数据均匀地分布到不同的分片表中,可以有效避免数据倾斜问题;由于数据已经被按照范围进行分片,支持频繁进行范围查询场景。

不仅如此,该算法支持动态的分片调整,可以根据实际业务数据的变化动态调整分片容量和范围,使得系统具备更好的扩展性和灵活性。

VOLUME_RANGE算法主要有三个属性:

ff8d3f9dfd6758db61d7fa45fb5ac748.png

看完是不是一脸懵逼,上界下界都是什么含义,我们实际使用一下就清晰了。为t_order逻辑表设置VOLUME_RANGE分片算法,range-lower下界数为 2,range-upper上界数为 20,分量容量sharding-volume 10。

yml核心配置如下:

# 分片算法定义
spring:
  shardingsphere:
    rules:
      sharding:
        # 自动分片表规则配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_volume_range
        sharding-algorithms:
          t_order_table_volume_range:
            type: VOLUME_RANGE
            props:
              range-lower: 2 # 范围下界,超过边界的数据会报错
              range-upper: 20 # 范围上界,超过边界的数据会报错
              sharding-volume: 10 # 分片容量
        tables:
          t_order: # 逻辑表名称
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
            ....
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_volume_range

这个配置的意思就是说,分片健t_order_id的值在界值 [range-lower,range-upper) 范围内,每个分片表最大存储 10 条数据;低于下界的值 [ 1,2 ) 数据分布到 t_order_0,在界值范围内的数据 [ 2,20 ) 遵循每满足 10 条依次放入 t_order_1、t_order_2;超出上界的数据[ 20,∞ ) 即便前边的分片表里未满 10条剩下的也全部放在 t_order_3。

那么它的数据分布应该如下:

  • [ 0,2 )数据分布到 t_order_0

  • [ 2,12 )数据分布到 t_order_1

  • [ 12,20 )数据分布到 t_order_2

  • [ 20,∞ )数据分布到 t_order_3

96e6d3c46f75e50a2dfbe3a8e7efc302.png基于分片容量的范围分片算法

接着准备插入40条数据,其中分片健字段t_order_id值从1~40,我们看到实际插入库的数据和上边配置的规则是一致的。超出range-lower、range-upper边界的部分数据,比如:t_order_2表未满 10条也不再插入,全部放入了t_order_3分片表中。

ce9702b75d38a8d269f9c34f23e10860.png
4、BOUNDARY_RANGE

基于分片边界的范围分片算法,和分片容量算法不同,这个算法根据数据的取值范围进行分片,特别适合按数值范围频繁查询的场景。该算法只有一个属性sharding-ranges为分片健值的范围区间。

5ab7a642fc15210bfb197c938144035b.png

比如,我们配置sharding-ranges=10,20,30,40,它的范围默认是从 0开始,范围区间前闭后开。配置算法以后执行建表语句,生成数据节点分布如:

db0-
   |_t_order_0
   |_t_order_2
   |_t_order_4
db1-
   |_t_order_1
   |_t_order_3

那么它的数据分布应该如下:

[ 0,10 )数据分布到t_order_0,

[ 10,20 )数据分布到t_order_1,

[ 20,30 )数据分布到t_order_2,

[ 30,40 )数据分布到t_order_3,

[ 40,∞ )数据分布到t_order_4。

40261e144e792fa21c66a1b902640796.png基于分片边界的范围分片算法

BOUNDARY_RANGE算法的YML核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 自动分片表规则配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_boundary_range
        sharding-algorithms:
          # 基于分片边界的范围分片算法
          t_order_table_boundary_range:
            type: BOUNDARY_RANGE
            props:
              sharding-ranges: 10,20,30,40 # 分片的范围边界,多个范围边界以逗号分隔
        tables:
          t_order: # 逻辑表名称
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
            ....
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_boundary_range

也插入40条数据,其中分片健字段t_order_id值从1~40,和上边分析的数据分布结果大致相同。看到第一张分片表中 t_order_0 只有 9 条数据,这是因为咱们插入数据的分片健值是从 1 开始,但算法是从 0 开始计算。

6101e3190bc14946be6f61bb8df3fab6.png
5、AUTO_INTERVAL

自动时间段分片算法,适用于以时间字段作为分片健的分片场景,和VOLUME_RANGE基于容量的分片算法用法有点类似,不同的是AUTO_INTERVAL依据时间段进行分片。主要有三个属性datetime-lower分片健值开始时间(下界)、datetime-upper分片健值结束时间(上界)、sharding-seconds单一分片表所能容纳的时间段。

ea70607dbc86b83eb4d53c9105935732.png

这里分片健已经从t_order_id替换成了order_date。现在属性 datetime-lower 设为 2023-01-01 00:00:00,datetime-upper 设为 2025-01-01 00:00:00,sharding-seconds为 31536000 秒(一年)。策略配置上有些改动,将分库和分表的算法全替换成AUTO_INTERVAL。

YML核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 自动分片表规则配置
        auto-tables:
          t_order:
            actual-data-sources: db$->{0..1}
            sharding-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_auto_interval
        # 分片算法定义
        sharding-algorithms:
          # 自动时间段分片算法
          t_order_table_auto_interval:
            type: AUTO_INTERVAL
            props:
              datetime-lower: '2023-01-01 00:00:00' # 分片的起始时间范围,时间戳格式:yyyy-MM-dd HH:mm:ss
              datetime-upper: '2025-01-01 00:00:00' #  分片的结束时间范围,时间戳格式:yyyy-MM-dd HH:mm:ss
              sharding-seconds: 31536000 # 单一分片所能承载的最大时间,单位:秒,允许分片键的时间戳格式的秒带有时间精度,但秒后的时间精度会被自动抹去
        tables:
          # 逻辑表名称
          t_order:
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
              standard:
                sharding-column: order_date
                sharding-algorithm-name: t_order_table_auto_interval
            # 分表策略
#            table-strategy:
#              standard:
#                sharding-column: order_date
#                sharding-algorithm-name: t_order_table_auto_interval

只要你理解了上边 VOLUME_RANGE 算法的数据分布规则,那么这个算法也很容易明白,分片健值在界值范围内 [datetime-lower,datetime-upper) 遵循每满足 sharding-seconds 时间段的数据放入对应分片表,超出界值的数据上下顺延到其他分片中。

它的数据分布应该如下:

  • [ 2023-01-01 00:00:00,2024-01-01 00:00:00 )数据分布到 t_order_0,

  • [ 2024-01-01 00:00:00,2025-01-01 00:00:00 )数据分布到 t_order_1,

  • [ 2025-01-01 00:00:00,2026-01-01 00:00:00 )数据分布到 t_order_2。

  • [ 2026-01-01 00:00:00,∞ )数据分布到 t_order_3。

为了方便测试,手动执行插入不同日期的数据,按照上边配置的规则应该t_order_0会有一条 23 年的数据,t_order_1 中有两条 24 年的数据,t_order_2 中有两条 25 年的数据,t_order_3 中有两条 26、27 年的数据。

// 放入 t_order_0 分片表
INSERT INTO `t_order` VALUES (1, '2023-03-20 00:00:00', 1, '1', 1, 1.00);
// 放入 t_order_1 分片表
INSERT INTO `t_order` VALUES (2, '2024-03-20 00:00:00', 2, '2', 2,1.00);
INSERT INTO `t_order` VALUES (3, '2024-03-20 00:00:00', 3, '3', 3, 1.00);
// 放入 t_order_2 分片表
INSERT INTO `t_order` VALUES (4,'2025-03-20 00:00:00',4, '4', 4, 1.00);
INSERT INTO `t_order` VALUES (5,'2025-03-20 00:00:00',5, '5', 5,  1.00);
// 放入 t_order_3 分片表
INSERT INTO `t_order` VALUES (6,'2026-03-20 00:00:00',6, '6', 6,  1.00);
INSERT INTO `t_order` VALUES (7,'2027-03-20 11:19:58',7, '7', 7,  1.00);

查看实际的数据分布情况和预想的结果完全一致,至此内置算法全部使用大成。

4105f203507d250f89a41bcf644259fb.png

标准分片算法

6、INLINE

行表达式分片算法,适用于比较简单的分片场景,利用Groovy表达式在算法属性内,直接书写分片逻辑,省却了配置和代码开发,只支持SQL语句中的 = 和 IN 的分片操作,只支持单分片键 。

ed64c671b71fc2a219b1d7391b242f29.png

该算法有两属性:

  • algorithm-expression:编写Groovy的表达式,比如: t_order_$->{t_order_id % 3} 表示根据分片健 t_order_id 取模获得 3 张 t_order 分片表 t_order_0 到 t_order_2。

  • allow-range-query-with-inline-sharding:由于该算法只支持含有 = 和 IN 操作符的SQL,一旦SQL使用了范围查询 >、< 等操作会报错。要想执行范围查询成功,该属性开启为true即可,一旦开启范围查询会无视分片策略,进行全库表路由查询,这个要慎重开启 !

YML核心配置如下:

spring:
  shardingsphere:
    # 具体规则配置
    rules:
      sharding:
        # 分片算法定义
        sharding-algorithms:
          # 标准分片算法
          # 行表达式分片算法
          t_order_table_inline:
            type: INLINE
            props:
              algorithm-expression: t_order_$->{order_id % 3} # 分片算法的行表达式
              allow-range-query-with-inline-sharding: false # 是否允许范围查询。注意:范围查询会无视分片策略,进行全路由,默认 false
        tables:
          # 逻辑表名称
          t_order:
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_algorithms
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_inline
7、INTERVAL

时间范围分片算法,针对于时间字段(字符串类型 )作为分片健的范围分片算法,适用于按照天、月、年这种固定区间的数据分片。上边使用其它时间分片算法时,用的都是t_order_n后缀编号格式的分片表。但业务上往往需要的可能是按月、年t_order_yyyyMM的这种分片表格式。

时间范围分片算法(INTERVAL),可以轻松实现这种场景,它的属性比较多,逐个解释下:

690ebb9bd30ff22019e617e75ff8831a.png
  • datetime-pattern:分片健值的时间格式,必须是Java DateTimeFormatter类支持的转换类型

  • datetime-lower:分片健值的下界,超过会报错,格式必须与datetime-pattern一致

  • datetime-upper:分片健值的上界,超过会报错,格式必须与datetime-pattern一致

  • sharding-suffix-pattern:分片表后缀名格式,yyyyMM、yyyyMMdd等格式,分片表格式的定义要结合datetime-interval-unit的单位,比如:t_order_yyyyMM格式表示分片表存的月的数据,t_order_yyyy格式表示分片表存的年的数据;

  • datetime-interval-unit:分片间隔单位,超过该时间间隔将进入下一分片。它遵循 Java ChronoUnit 枚举,比如:MONTHS、DAYS等;

  • datetime-interval-amount:分片间隔数,和datetime-interval-unit是紧密配合使用;

接下来实现个按月存储数据的场景,用t_order_202401~t_order_202406 6张分片表存储前半年的数据,每张分片表存储一个月的数据。interval_value字段作为分片健,时间字符串类型,允许的分片值时间范围 2024-01-01 00:00:00~2024-06-30 23:59:59 不在范围内插入报错。

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定义
        sharding-algorithms:
          t_order_database_mod:
            type: MOD
            props:
              sharding-count: 2 # 指定分片数量
          t_order_table_interval:
            type: INTERVAL
            props:
              datetime-pattern: "yyyy-MM-dd HH:mm:ss"  # 分片字段格式
              datetime-lower: "2024-01-01 00:00:00"  # 范围下限
              datetime-upper: "2024-06-30 23:59:59"  # 范围上限
              sharding-suffix-pattern: "yyyyMM"  # 分片名后缀,可以是MM,yyyyMMdd等。
              datetime-interval-amount: 1  # 分片间隔,这里指一个月
              datetime-interval-unit: "MONTHS" # 分片间隔单位
        tables:
          # 逻辑表名称
          t_order:
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${202401..202406}
            # 分库策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_mod
            # 分表策略
            table-strategy:
              standard:
                sharding-column: interval_value
                sharding-algorithm-name: t_order_table_interval
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

配置完成后插入测试数据 1月~7月,正常情况下前 6 个月的数据会正常插入,超过界值的 7月数据应该会报错。

// 放入 t_order_202401 分片表
INSERT INTO `t_order` VALUES (1, 1, '1', 1, 1.00, '2024-01-01 00:00:00', 1);
// 放入 t_order_202402 分片表
INSERT INTO `t_order` VALUES (2, 2, '2', 2, 1.00, '2024-02-01 00:00:00', 1);
// 放入 t_order_202403 分片表
INSERT INTO `t_order` VALUES (3, 3, '3', 3, 1.00, '2024-03-01 00:00:00', 1);
// 放入 t_order_202404 分片表
INSERT INTO `t_order` VALUES (4, 4, '4', 4, 1.00, '2024-04-01 00:00:00', 1);
// 放入 t_order_202405 分片表
INSERT INTO `t_order` VALUES (5, 5, '5', 5, 1.00, '2024-05-01 00:00:00', 1);
// 放入 t_order_202406 分片表
INSERT INTO `t_order` VALUES (6, 6, '6', 6, 1.00, '2024-06-01 00:00:00', 1);

// 插入会报错
INSERT INTO `t_order` VALUES (7, 7, '7', 7, 1.00, '2024-07-01 00:00:00', 1);

看到实际的入库的效果和预期的一致,一月的数据存到t_order_202401,二月的数据存到t_order_202402~,在插入 7月数据的时候报错了。

96675476031650baf003c41020eb588f.png

COSID 类型算法

ShardingSphere 提供了三种基于散列散列算法的CosId(它是一款性能极高分布式ID生成器)分片算法,这个算法的核心思想是通过散列算法对CosId生成的分布式ID和分片键值进行处理,以确定数据应该存放在哪个具体的数据节点上。

使用散列算法的优势,可以将数据按照一定规则映射到不同的数据节点上,能够确保数据的均匀分布,避免某些节点负载过重或者数据倾斜的情况。

三个算法与其他分片算法主要区别在于底层的实现,在配置上使用上基本没太多区别。

8、COSID_MOD

基于 CosId 的取模分片算法和普通的MOD算法使用上略有不同,mod为分片数量,logic-name-prefix分片数据源或真实表的前缀格式。

4d8d3a0edbb5e849d8617818ee10e59e.png

yml核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定义
        sharding-algorithms:
          t_order_database_mod:
            type: MOD
            props:
              sharding-count: 2 # 指定分片数量
          # 8、基于 CosId 的取模分片算法
          t_order_table_cosid_mod:
            type: COSID_MOD
            props:
              mod: 3  # 分片数量
              logic-name-prefix: t_order_ # 分片数据源或真实表的前缀格式
        tables:
          # 逻辑表名称
          t_order:
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_mod
            # 分表策略
            table-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_table_cosid_mod
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake
9、COSID_INTERVAL

基于 CosId 的固定时间范围的分片算法,和INTERVAL算法的用法很相似,不同点在于增加了zone-id时区属性,logic-name-prefix分片数据源或真实表的前缀格式,上下界datetime-lower、datetime-upper范围的时间格式是固定的yyyy-MM-dd HH:mm:ss。

e20294fe9be4466e22c43fe5ee54d103.png

yml核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定义
        sharding-algorithms:
          t_order_database_mod:
            type: MOD
            props:
              sharding-count: 2 # 指定分片数量
          # 基于 CosId 的固定时间范围的分片算法
          t_order_table_cosid_interval:
            type: COSID_INTERVAL
            props:
              zone-id: "Asia/Shanghai" # 时区,必须遵循 java.time.ZoneId 的所含值。 例如:Asia/Shanghai
              logic-name-prefix: t_order_ # 分片数据源或真实表的前缀格式
              sharding-suffix-pattern: "yyyyMM" # 分片数据源或真实表的后缀格式,必须遵循 Java DateTimeFormatter 的格式,必须和 datetime-interval-unit 保持一致。例如:yyyyMM
              datetime-lower: "2024-01-01 00:00:00" # 时间分片下界值,格式与 yyyy-MM-dd HH:mm:ss 的时间戳格式一致
              datetime-upper: "2024-12-31 00:00:00" # 时间分片上界值,格式与 yyyy-MM-dd HH:mm:ss 的时间戳格式一致
              datetime-interval-unit: "MONTHS" # 分片键时间间隔单位,必须遵循 Java ChronoUnit 的枚举值。例如:MONTHS
              datetime-interval-amount: 1 # 分片键时间间隔,超过该时间间隔将进入下一分片
        tables:
          # 逻辑表名称
          t_order:
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${202401..202412}
            # 分库策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_mod
            # 分表策略
            table-strategy:
              standard:
                sharding-column: interval_value
                sharding-algorithm-name: t_order_table_cosid_interval
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake
10、COSID_INTERVAL_SNOWFLAKE

基于 CosId 的雪花ID固定时间范围的分片算法,和上边的COSID_INTERVAL算法不同之处在于,底层用于散列的COSID的生成方式是基于雪花算法(Snowflake),内部结合了时间戳、节点标识符和序列号等,这样有助于数据分布更均匀些。

8f5c50c3172bba7235975a4505f885fa.png

使用除了type类型不同COSID_INTERVAL_SNOWFLAKE外,其他属性用法和COSID_INTERVAL完全一致。yml核心配置如下:

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定义
        sharding-algorithms:
          t_order_database_mod:
            type: MOD
            props:
              sharding-count: 2 # 指定分片数量
          # 基于 CosId 的固定时间范围的分片算法
          t_order_table_cosid_interval_snowflake:
            type: COSID_INTERVAL_SNOWFLAKE
            props:
              zone-id: "Asia/Shanghai" # 时区,必须遵循 java.time.ZoneId 的所含值。 例如:Asia/Shanghai
              logic-name-prefix: t_order_ # 分片数据源或真实表的前缀格式
              sharding-suffix-pattern: "yyyyMM" # 分片数据源或真实表的后缀格式,必须遵循 Java DateTimeFormatter 的格式,必须和 datetime-interval-unit 保持一致。例如:yyyyMM
              datetime-lower: "2024-01-01 00:00:00" # 时间分片下界值,格式与 yyyy-MM-dd HH:mm:ss 的时间戳格式一致
              datetime-upper: "2024-12-31 00:00:00" # 时间分片上界值,格式与 yyyy-MM-dd HH:mm:ss 的时间戳格式一致
              datetime-interval-unit: "MONTHS" # 分片键时间间隔单位,必须遵循 Java ChronoUnit 的枚举值。例如:MONTHS
              datetime-interval-amount: 1 # 分片键时间间隔,超过该时间间隔将进入下一分片
        tables:
          # 逻辑表名称
          t_order:
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${202401..202412}
            # 分库策略
            database-strategy:
              standard:
                sharding-column: order_id
                sharding-algorithm-name: t_order_database_mod
            # 分表策略
            table-strategy:
              standard:
                sharding-column: interval_value
                sharding-algorithm-name: t_order_table_cosid_interval_snowflake
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

复合分片算法

11、COMPLEX_INLINE

复合行表达式分片算法,适用于多分片健的简单分片场景,和行表达式分片算法使用的方式基本一样。多了一个属性sharding-columns分片列名称,多个列用逗号分隔。特别注意:使用多分片键复合算法,一定要基于复合分片策略进行设置 。

2b76019aac31699f65051d50082349cb.png

我们对现有的分库分表算法进行了改进,将分片策略修改为complex,sharding-columns单个分片键升级为多个分片键逗号分隔。例如,将分库表达式从db$->{order_id % 2}调整为db$->{(order_id + user_id) % 2},就实现了多个分片键的应用。

yml核心的配置如下:

spring:
  shardingsphere:
    # 具体规则配置
    rules:
      sharding:
        # 分片算法定义
        sharding-algorithms:
          t_order_database_complex_inline_algorithms:
            type: COMPLEX_INLINE
            props:
              sharding-columns: order_id, user_id # 分片列名称,多个列用逗号分隔。
              algorithm-expression: db$->{(order_id + user_id) % 2} # 分片算法的行表达式
              allow-range-query-with-inline-sharding: false # 是否允许范围查询。注意:范围查询会无视分片策略,进行全路由,默认 false
          # 11、复合行表达式分片算法
          t_order_table_complex_inline:
            type: COMPLEX_INLINE
            props:
              sharding-columns: order_id, user_id # 分片列名称,多个列用逗号分隔。
              algorithm-expression: t_order_$->{ (order_id + user_id) % 3 } # 分片算法的行表达式
              allow-range-query-with-inline-sharding: false # 是否允许范围查询。注意:范围查询会无视分片策略,进行全路由,默认 false
        tables:
          # 逻辑表名称
          t_order:
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
              complex:
                shardingColumns: order_id, user_id
                sharding-algorithm-name: t_order_database_complex_inline_algorithms
            # 分表策略
            table-strategy:
              complex:
                shardingColumns: order_id, user_id
                sharding-algorithm-name: t_order_table_complex_inline
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

Hint 分片算法

12、HINT_INLINE

Hint 行表达式分片算法(强制路由分片算法),允许我们指定数据分布的分片库和分表的位置。这个算法只有一个属性algorithm-expression,直接利用Groovy表达式在其中书写分片逻辑。

如果想要向db0.t_order_1分片表中插入一条数据,但我的 Insert SQL 中并没有分片健呀,执意执行插入操作可能就会导致全库表路由,插入的数据就会重复,显然是不能接受的。Hint 算法可以很好的解决此场景。

HINT_INLINE 算法一定要在 HINT 分片策略内使用 ,否则会报错。

核心的配置如下:其中两个表达式db$->{Integer.valueOf(value) % 2}和t_order_$->{Integer.valueOf(value) % 3}中的value值分别是我们通过 Hint API 传入的分库值和分表值。

spring:
  shardingsphere:
    rules:
      sharding:
        # 分片算法定义
        sharding-algorithms:
          # Hint 行表达式分片算法
          t_order_database_hint_inline:
            type: HINT_INLINE
            props:
              algorithm-expression: db$->{Integer.valueOf(value) % 2} # 分片算法的行表达式,默认值${value}
          t_order_table_hint_inline:
            type: HINT_INLINE
            props:
              algorithm-expression: t_order_$->{Integer.valueOf(value) % 3} # 分片算法的行表达式,默认值${value}
        tables:
          # 逻辑表名称
          t_order:
            # 数据节点:数据库.分片表
            actual-data-nodes: db$->{0..1}.t_order_${0..2}
            # 分库策略
            database-strategy:
              hint:
                sharding-algorithm-name: t_order_database_hint_inline
            # 分表策略
            table-strategy:
              hint:
                sharding-algorithm-name: t_order_table_hint_inline
            keyGenerateStrategy:
              column: id
              keyGeneratorName: t_order_snowflake

配置完分片算法,如何将value值传递进来?通过HintManager设置逻辑表的分库addDatabaseShardingValue、分表addTableShardingValue,强制数据分布到指定位置。

@DisplayName("测试 hint_inline 分片算法插入数据")
@Test
public void insertHintInlineTableTest() {
      HintManager hintManager = HintManager.getInstance();
      hintManager.clearShardingValues();
      // 设置逻辑表 t_order 的分库值
      hintManager.addDatabaseShardingValue("t_order", 0);
      // 设置逻辑表 t_order 的分表值
      hintManager.addTableShardingValue("t_order", 1);
      // 1%3 = 1 所以放入 db0.t_order_1 分片表
      jdbcTemplate.execute("INSERT INTO `t_order`(`id`,`order_date`,`order_id`, `order_number`, `customer_id`, `total_amount`, `interval_value`, `user_id`) VALUES (1, '2024-03-20 00:00:00', 1, '1', 1, 1.00, '2024-01-01 00:00:00', 1);");
      hintManager.close();
}

ShardingSphere 通过使用ThreadLocal管理强制路由配置,可以通过编程的方式向HintManager中添加分片值,该分片值仅在当前线程内生效。

  • HintManager.getInstance() 获取 HintManager 实例;

  • HintManager.addDatabaseShardingValue,HintManager.addTableShardingValue 方法设置分片键值;

  • 执行 SQL 语句完成路由和执行;

  • 最后调用 HintManager.close 清理 ThreadLocal 中的内容。

按我们设定的数据节点位置,插入一条测试数据,看到确实存在了db0.t_order_1中,完美!

da912e84ef93a0c43d23e48a8b11a1f3.png

总结

本文中我们讲解了ShardingSphere-jdbc所支持的12种分片算法,每种算法都具有独特的特点。在实际应用中,需要结合具体的业务场景来灵活选择和应用适合的分片算法。


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,“长按”或“扫描”下方二维码噢:

a5291428c7c96b56cfebe321881b0f77.png

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

00b2299330b0cdb2a824fde6db788161.png

63d51250afd462d0254efeca2364d363.pngf3287fe356cad522b023164408d31df2.png222ffe8d306ae722a3139e66363d25ce.png7189cbaba32236dcd8a880b445fc3421.png

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
从RRT到平滑轨迹:机械臂避障规划仿真全流程解析 本文详细解析了机械臂避障规划从RRT算法到平滑轨迹优化的全流程,包括MATLAB实现、碰撞检测工程实践及轨迹平滑优化技巧。通过RRT算法在关节空间的路径搜索与Minimum Jerk/Snap优化,实现机械臂在复杂环境中的高效安全运动,适用于工业自动化与机器人控制领域。 阅读详情

相关推荐

LeGO-LOAM运行kitti数据集

文章目录1. kitti-lego-loam2. 改动3. 实验结果4. evo轨迹测评 1. kitti-lego-loam 链接:kitti-lego-loam kitti-lego-loam提供了将kitti序列转化成rosbag的代码,在kittibag中. 需要注意下数据文件的存放顺序,以00序列为例: datafolder          |____results          &

Zlp19970106的博客 8705

一文搞懂分库分表算法,通俗易懂(基因法、一致性 hash、时间维度)

原因也很好理解,拿我改造过后的雪花算法来说,变量只有累加位,累加 bit 位只留 5 位,也就是最大累加 2 的 5 次方(32),累加到 4(00100)时一切正常 00100 正常参与或运算,累加到 36(100100)时,二进制有 6 位,和我们规定的 5 位超了一位,有效参与到计算的实际上是 00100,这时候变量累加位也一致了,恰好此时第 100100 的第一位 1 参与或运算对结果没影响,此时的订单号是不是就重复了!其他年的数据同理比对迁移,这个迁移好办对整个库迁移,直接改配置文件就行。

JmuziA的博客 3216

MediaCodec视频解码流程详解及参考demo

本文主要讲解mediacodec的视频解码流程,及demo参考例子。

分享音视频技术 7877

一口气搞懂分库分表 12 种分片算法,大厂都在用

本文是《ShardingSphere5.x分库分表原理与实战》系列的第五篇文章,我们一起梳理下框架中的核心部分分片策略和分片算法,其内部针为我们提供了多种分片策略和分片算法,来应对不同的业务场景,本着拿来即用的原则。这次将详细介绍如何在中实战 5 种分片策略和 12 种分片算法,自定义分片算法,比较它们的应用场景以及优劣。全部demo案例GitHub。

竹林幽深 694

纽扣电池供电系统优化:NBM5100A与STM32F745VG组合方案

在低功耗物联网设备设计中,能量管理是核心挑战之一。纽扣电池因其体积小、成本低被广泛采用,但瞬时大电流需求常导致电压骤降和寿命缩短。通过超级电容缓冲技术,可以实现能量的细水长流式存储与集中释放。NBM5100A电源管理IC与STM32F745VG微控制器的组合方案,采用双阶段能量管理架构,先以恒定小电流充电,再通过电容释放大电流。这种方案不仅能提升系统稳定性,还能延长电池寿命3-5倍,特别适合智能门锁、无线传感器等需要间歇性高功率输出的场景。

weixin_29194255的博客 257

Unity UGUI深度优化

Unity UGUI优化相关

不定时分享所学所得,包括游戏开发和其他收获! 2719

mysql sharding 选型_sharding-jdbc 分库分表的 4种分片策略,还蛮简单的

一文快速入门分库分表中间件 Sharding-JDBC (必修课)​mp.weixin.qq.com上文中介绍了 sharding-jdbc 的基础概念,还搭建了一个简单的数据分片案例,但实际开发场景中要远比这复杂的多,我们会按 SQL 中会出现的不同操作符 >、往下开展前先做个答疑,前两天有个小伙伴私下问了个问题说:如果我一部分表做了分库分表,另一部分未做分库分表的表怎么处理?怎么才能正常...

weixin_30045055的博客 1453

Mac上除了Homebrew,这几种安装ADB的方法你可能也需要知道(含手动配置避坑)

本文全面解析Mac上五种ADB安装方案,从Homebrew到手动配置,涵盖常见问题解决与环境变量配置。特别针对macOS High Sierra等老旧系统提供专属解法,帮助开发者高效安装Android Debug Bridge(ADB),避免常见陷阱,提升开发效率。

weixin_42546392的博客 322

MySQL-运维-分库分表-分片规则

定义一个时间周期,例如以10天为一个周期,在第一个周期中录入的所有数据存入第一个分片。同理,第二个周期中的数据放入第二个分片。如果分片满了,那么重头开始。

rch041126的博客 316

Ollama模型路径迁移实战:Windows/Mac/Linux三平台保姆级教程(附常见问题排查)

本文提供了一份详细的Ollama模型路径迁移教程,涵盖Windows、macOS和Linux三大平台。通过设置OLLAMA_MODELS环境变量或创建符号链接,指导用户将模型从默认路径安全迁移至新位置,以释放系统盘空间或提升性能。教程包含迁移前的准备、分平台步骤、迁移后的验证以及常见问题排查,确保迁移过程平滑可靠。

js777的博客 1184

QCM2290 PM-3 如何让mirco-usb支持关机充电

PM4125-3插入type-C触发开机进入关机充电的CC脚中断条件是否可以软件上屏蔽, 做到只通过VBUS中断即可触发进入关机充电模式,达到和PM4125-2的效果一样只要插入micro USB 就可以触发进入关机充电模式。硬件团队提议修改寄存器 SCHG_L_MISC_SYSOK_CFG 0x164A bit[4] 目前修改如下 — a/BOOT.XF.4.1/boot_images/QcomPkg/Library/PmicLib/target/Agatti_pmCocos/psi/pm_confi

墨染天玑的博客 444

数据库分片(分库分表)

简要的介绍为什么要分库分片,怎么去分库分表,分库分表带来的问题。

qq_35746400的博客 332

YOLOv10 的损失函数解析

YOLOv10 在 YOLO 系列的演进中进一步优化了任务解耦与动态平衡策略,通过 ​多模态损失融合、自适应样本分配 和 ​轻量化设计,显著提升了检测精度与推理效率。

浩瀚之水的专栏 1378

一线大厂互联网公司常用MySQL分库分表方案

面试前一定少不了刷题,为了方便大家复习,我分享一波个人整理的面试大全宝典Java核心知识整理Java核心知识Spring全家桶(实战系列)其他电子书资料Step3:刷题既然是要面试,那么就少不了刷题,实际上春节回家后,哪儿也去不了,我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。以下是我私藏的面试题库:《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》

2401_84408249的博客 1116

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

mysql:分库分表深度解析

fill:#333;color:#333;color:#333;fill:none;是单表数据增长是否触发阈值?选择拆分维度拆分方式水平拆分垂直拆分选择分片键业务维度拆分确定分片算法实施迁移。

weixin_43290370的博客 761

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

mysql:分库分表全链路实施方案从架构设计到平滑迁移

通过系统化的分库分表实施方案,结合业务特点选择合适的分片策略,并配套完善的迁移方案和治理体系,可以有效解决单库单表的性能瓶颈问题,为业务发展提供可持续的数据库架构支撑。查询订单(orderId=789)解析orderId获取userId。插入订单(userId=123)计算分片: userId%2=1。计算分片: userId%2=1。

weixin_43290370的博客 907

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

MySQL 系列:第29篇 分库分表与分布式扩展

摘要: 分库分表是解决单机数据库性能瓶颈的关键方案,通过将数据分散到多台MySQL实例实现水平扩展。文章对比了垂直拆分(按业务模块)和水平拆分(按数据行)的优劣,重点讲解了水平拆分的HASH分片和RANGE分片策略及其适用场景。针对分库分表后的全局唯一ID问题,详细介绍了雪花算法(Snowflake)的原理与Python实现,并分析了其优缺点。该方案适合高并发场景,但需注意时钟回拨问题。

IT策士的博客 223

数据库与缓存--分库分表实战指南

分库分表核心原理与实践摘要 本文系统介绍了分库分表技术,涵盖其必要性、实现方式和最佳实践。分库分表主要解决单表数据量大、高并发和单点故障问题,分为垂直拆分(按业务/字段)和水平拆分(按数据分布)。关键设计包括分片策略选择(Hash/Range/一致性Hash)、主键设计(推荐雪花算法)和中间件选型(如ShardingSphere)。实战部分展示了订单系统的分库分表实现,包括数据源配置和跨库查询解决方案。文章提供了完整的架构图、配置示例和代码片段,帮助开发者掌握这一高并发场景下的关键技术。

刘~浪地球的博客 427

分库分表扩容治理(下):跨分片查询优化与生产踩坑全解(完整全文)

本文配套 ShardingSphere 可运行源码、四层查询落地方案、CQRS 宽表架构与生产踩坑清单,同时补充分库分表柔性事务、全局唯一约束等高频问题的落地要点,适合后端开发、DBA、架构师进阶落地。

一线 Java 开发,专注 Java 核心原理、生产踩坑与架构面试实战。 758
上一篇: 记一次使用规则引擎改造任务系统的经验
下一篇: Spring Boot3集成iText实现PDF导出功能
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值