ShardingSphere笔记(二):自定义分片算法 — 按月分表
文章目录
一、准备
- 这里我是用的 ShardingSphere 的版本是 5.2.1
- 实现方式参考了官方的 SardingSphere 自定义分片算法的 demo,官方的demo中的分片算法是按照订单Id取模。这里我扩展为了根据时间按月分表。
- 官方提供了两种方式来定义自定义的分表算法:
- 一种方式是 SPI 的方式,也就是需要在项目的 resource/META-INF/services 目录下按照 SPI的方式注册算法类。官方demo位置: https://github.com/apache/shardingsphere/tree/master/examples/shardingsphere-jdbc-example/single-feature-example/extension-example/custom-sharding-algortihm-example/spi-based-sharding-algorithm-example/
- 另一种方式是经典方式,不需要创建services文件,但是在注册算法的时候需要写上类的全类名。官方demo位置:https://github.com/apache/shardingsphere/tree/master/examples/shardingsphere-jdbc-example/single-feature-example/extension-example/custom-sharding-algortihm-example/class-based-sharding-algorithm-example
- 我参考的方式是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 并且实现了两个方法 :
- String doSharding(Collection<String>, PreciseShardingValue<Long>)
- 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 方式
- 确定需要分表的字段和字段类型。
- 继承 StandardShardingAlgorithm, 实现其中的两个分片方法。实现 getType() 方法,返回该算法的 SPI 名称,在配置文件中配置算法的时候需要用到该名称。
- 通过SPI的方式注册该算法
- 在配置文件中配置该算法
2. 经典模式
- 确定需要分表的字段和字段类型。
- 继承 StandardShardingAlgorithm, 实现其中的两个分片方法。
- 在配置文件中配置该算法
四、按月分表算法(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

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

被折叠的 条评论
为什么被折叠?



