闲谭SpringBoot--ShardingSphere分库分表探究
文章目录
- 1. 背景
- 2. 创建数据库
- 3. 修改yml配置文件
- 4. 分片算法类
- 5. 测试
- 6 小结
1. 背景
接上文,我们对日志表,进行了按月的分表,这样每个月几百万条数据量还是扛得住的。
但是如果数据再多呢,除了提高硬件性能,还有一个可以考虑的方案就是分库。
例如,我们通过数据所属的地域、公司、部门等进行分库划分,当然具体根据什么划分,由需求决定。
本篇我们在上一篇《闲谭SpringBoot–ShardingSphere分表探究》的基础上,对日志表进一步按机构进行划分。
2. 创建数据库
首先创建两个数据库test、test1,每个数据库中都放入log_202411、log_202412、log202501、log_202502四张表,四张表结构是一样的如下:
注意,我们想实现按机构编号departId分库,然后同一个机构的数据,根据time再按月分表。
CREATE TABLE `log_202411` (
`id` bigint(20) NOT NULL,
`content` varchar(255) DEFAULT '',
`time` datetime DEFAULT NULL,
`departId` bigint(20) DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
3. 修改yml配置文件
配置两个数据库,注意ds0和ds1分别对应数据库test/test1。
配置分片方式,首先配置默认的库:
然后针对log表配置分片规则,如下表达式意味着:对log表来说,数据库是ds加一个字符串,表则是log加一个字符串,至于加什么字符串,由分片算法指定。
接下来就是分片算法了,注意按机构分库我们只需要使用=和IN操作,所以只需要配置精确分片算法即可。
而时间还需要范围查询,所以按时间分表还需要一个范围分片算法。
完整配置如下:
server:
port: 8080
servlet:
context-path: /sharding
spring:
shardingsphere: # 数据库配置
sharding:
default-data-source-name: ds0 #注意:不分库时,默认的数据库源
default-database-strategy: #默认的分库策略
inline:
sharding-column: id
algorithm-expression: ds0
tables: #数据分片规则配置
log: # 逻辑表名称
actual-data-nodes: ds${0..1}.log$->{1..2} # 由数据源名 + 表名组成(参考 Inline 语法规则)
database-strategy: # 分库策略
standard:
precise-algorithm-class-name: org.example.sharding.config.DepartPreciseShardingAlgorithm # 精确分片算法类名称,用于=和IN
sharding-column: departId # 分片列名称
table-strategy: # 分表策略
standard: # 行表达式分片策略
precise-algorithm-class-name: org.example.sharding.config.MonthPreciseShardingAlgorithm # 精确分片算法类名称,用于=和IN
sharding-column: time # 分片列名称
range-algorithm-class-name: org.example.sharding.config.MonthRangeShardingAlgorithm # 范围分片算法类名称,用于BETWEEN
key-generator: # key生成器
column: id
type: SNOWFLAKE # SnowflakeShardingKeyGenerator
props:
worker: # SNOWFLAKE算法的worker.id
id: 100
max: # SNOWFLAKE算法的max.tolerate.time.difference.milliseconds
tolerate:
time:
difference:
milliseconds: 20
datasource:
names: ds0,ds1
ds0:
type: com.alibaba.druid.pool.DruidDataSource
name: test
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&allowMultiQueries=true
username: root
password: 123456
ds1:
type: com.alibaba.druid.pool.DruidDataSource
name: test1
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&allowMultiQueries=true
username: root
password: 123456
4. 分片算法类
编写按机构分库算法类:
/**
* 按机构精确分片算法类
*/
/**
* 按机构精确分片算法类
*/
@Slf4j
public class DepartPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) {
// 获取分片键值
Object object = shardingValue.getValue();
Integer num = 0;//默认分片序号
try {
num = Integer.parseInt(object.toString()) % 2;//机构id为偶数,数据进入ds0;机构id为奇数,数据进入ds1;
} catch (Exception e) {
log.error("按机构精确分片算法类报错:{}", e.getMessage());
}
// 返回要进入的表名称
String tableName = "ds" + num;
log.info("精确分片结果:{}", tableName);
return tableName;
}
}
5. 测试
接下来发起测试,我们测试一个机构id为偶数的例子:
通过断点查看分片情况,首先触发了分库分片算法,数据进入ds0
然后触发了分表分片算法:
所以数据会进入ds0库的log_202501表。
然后我们测试下查询:
运行后分片结构如下:
说明我们的分片算法是正确的。
6 小结
通过分库分表,支持每月千万级数据量问题基本不大。
如果再多,每月上亿、十亿、百亿级别,哈哈,我也不知道啦,因为我还没遇到过。