ShardingSphere笔记(二):自定义分片算法 — 按月分表

本文介绍如何使用ShardingSphere实现自定义分片算法,以按月分表为例,详细讲解了分表逻辑及SPI配置过程。

ShardingSphere笔记(二):自定义分片算法 — 按月分表

一、准备

  1. 这里我是用的 ShardingSphere 的版本是 5.2.1
  2. 实现方式参考了官方的 SardingSphere 自定义分片算法的 demo,官方的demo中的分片算法是按照订单Id取模。这里我扩展为了根据时间按月分表。
  3. 官方提供了两种方式来定义自定义的分表算法:
  4. 我参考的方式是SPI的方式,项目中使用的是mybatis,所以参考的是里面的 mybatis 的demo

二、分表逻辑

在写分片算法之前,我们需要搞清楚,ShardingSphere 这个框架是怎么做分片的?在上一篇笔记里面我简单提到了 ShardingSphere 是通过解析Sql达到分片的目的的。

我们看一看官方是怎么做分片的:SPIBasedOrderStandardShardingAlgorithmFixture

public final class SPIBasedOrderStandardShardingAlgorithmFixture implements StandardShardingAlgorithm<Long> {
   
   
    
	//......
	
    @Override
    public String doSharding(final Collection<String> availableTargetNames, final PreciseShardingValue<Long> shardingValue) {
   
   
        for (String each : availableTargetNames) {
   
   
            if (each.endsWith(shardingSuffix(shardingValue.getValue()))) {
   
   
                return each;
            }
        }
        return null;
    }
    
    private String shardingSuffix(final Long shardingValue) {
   
   
        return "_" + (shardingValue % 2);
    }
    
    @Override
    public Collection<String> doSharding(final Collection<String> availableTargetNames, final RangeShardingValue<Long> shardingValue) {
   
   
        return availableTargetNames;
    }

}

可以看到,官方的demo中 继承了 StandardShardingAlgorithm 并且实现了两个方法 :

  1. String doSharding(Collection<String>, PreciseShardingValue<Long>)
  2. Collection<String> doSharding(Collection<String> , RangeShardingValue<Long>)

这两个方法就是分表逻辑了:

  • 这里类的泛型是 Long 的原因就是官方文档中的分表列是订单号,订单号类型就是Long,就是说这个算法你要应用到数据表的哪一个字段,那么这个泛型的类型就是这个字段的类型。
  • 第一个方法是精确匹配,可以发现 PreciseShardingValue 只有一个获取值的方法 getValue() ,意味着这个方法是来匹配到那些精确匹配的sql, 比如说 select * from t_order where order_id = 1。 根据 order_id 做分片,那么ShardingSphere在做分片路由的时候就会调用第一个方法,你通过 PreciseShardingValue.getValue() 就可以拿到等于号后面的值。
  • 第二个方法是范围匹配, RangeShardingValue 有一个 getValueRange() 方法,返回的对象提供了lowerEndpoint() 和 upperEndpoint() 两个方法。比如你调用 select * from t_order where order_id > 1 and order_id < 10, 那么就会调用该方法来进行路由,这里的lowerEndPoint 就是1, uperEndpoint 就是10。
  • 精确匹配的方法返回了一个结果,范围匹配的返回了一个集合,原因就是一条记录不能可能存到两个表中,第一个方法就是来精确定位一条记录应该被路由到哪一个表。
  • 该算法不仅仅是可以用在路由表,也可以用在路由数据库
    • 当它作为数据库分片算法的时候,方法中的第一个参数是可用的数据源名称列表。
    • 当它作为数据表分表算法的时候第一个参数是可用的数据表列表。
    • 因为ShardingSphere本身就是做 分库+分表 的框架,所以事实上 分库算法 + 分表算法 才算的上是完整的分片算法。如果我们配置了多个数据源,并且只配置了分表算法而没有做分库算法那么shardingsphere就只会走配置的第一个数据源。

通过上面的解释,也就能明白官方的 demo 分表算法到底是怎么做的分表的了。这个demo逻辑非常简单,就是把数据路由到了两个表中,一个是 table_name_0, 一个是 table_name_1。 因为他分表的时候就只是很简单的对2取模。当id是2的倍数时路由到后缀名为 0 的表,当id不是2的倍数时路由到 1 的表。

通过配置文件我们也能看到,它确实只分了两个表。

# 这里只配置了一个数据源和两张表,分别是 ds.t_order_0 和 ds.t_order_1, 根据 order_id 分表
spring.shardingsphere.rules.sharding.tables.t_order.actual-data-nodes=ds.t_order_$->{0..1}
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-column=order_id
spring.shardingsphere.rules.sharding.tables.t_order.table-strategy.standard.sharding-algorithm-name=t-order-spi-based

# 这里只配置了一个数据源和两张表,分别是 ds.t_order_item_0 和 ds.t_order_item_1, 根据 order_id 分表
spring.shardingsphere.rules.sharding.tables.t_order_item.actual-data-nodes=ds.t_order_item_$->{0..1}
spring.shardingsphere.rules.sharding.tables.t_order_item.table-strategy.standard.sharding-column=order_id
spring.shardingsphere.rules.sharding.tables.t_order_item.table-strategy.standard.sharding-algorithm-name=t-order-item-spi-based

另外,上面的demo是摘自 spi 方式的代码,经典模式的逻辑比这个多了个取模数的配置,而不是像上面一样写死为了2。有兴趣的可以去看看,基本逻辑是一致的。

三、自定义分片算法步骤(以按月分表为例)

假设我们的数据表名称为 test_data。 表中的时间列为 acquisition_time。根据该列作为分片的列。

1. SPI 方式

  1. 确定需要分表的字段和字段类型。
  2. 继承 StandardShardingAlgorithm, 实现其中的两个分片方法。实现 getType() 方法,返回该算法的 SPI 名称,在配置文件中配置算法的时候需要用到该名称。
  3. 通过SPI的方式注册该算法
  4. 在配置文件中配置该算法

2. 经典模式

  1. 确定需要分表的字段和字段类型。
  2. 继承 StandardShardingAlgorithm, 实现其中的两个分片方法。
  3. 在配置文件中配置该算法

四、按月分表算法(SPI方式)

经典模式和SPI方式配置方式只有在配置文件中的配置方式有一点点不一样。

在这之前需要引入 Shardingsphere的依赖,因为我这里是Springboot项目,直接引入的 starter.
另外

  • 因为需要连接mysql,引入了 mysql-connector-java
  • 使用了mybatis访问数据库,引入了 mybatis-plus-boot-starter
  • 用到了一些工具类,引入了 hutool-all
  • 用到了Hikari连接池,引入了 jdbc-starter
 	<properties>
        <maven.compiler.source>14</maven.compiler.source>
        <maven.compiler.target>14</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <shardingsphere-jdbc.version>5.2.1</shardingsphere-jdbc.version>
        <snakeyaml.version>1.33</snakeyaml.version>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
            <version
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值