文章目录
- 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: 8080servlet:context-path: /sharding
spring:shardingsphere: # 数据库配置sharding:default-data-source-name: ds0 #注意:不分库时,默认的数据库源default-database-strategy: #默认的分库策略inline:sharding-column: idalgorithm-expression: ds0tables: #数据分片规则配置log: # 逻辑表名称actual-data-nodes: ds${0..1}.log$->{1..2} # 由数据源名 + 表名组成(参考 Inline 语法规则)database-strategy: # 分库策略standard:precise-algorithm-class-name: org.example.sharding.config.DepartPreciseShardingAlgorithm # 精确分片算法类名称,用于=和INsharding-column: departId # 分片列名称table-strategy: # 分表策略standard: # 行表达式分片策略precise-algorithm-class-name: org.example.sharding.config.MonthPreciseShardingAlgorithm # 精确分片算法类名称,用于=和INsharding-column: time # 分片列名称range-algorithm-class-name: org.example.sharding.config.MonthRangeShardingAlgorithm # 范围分片算法类名称,用于BETWEENkey-generator: # key生成器column: idtype: SNOWFLAKE # SnowflakeShardingKeyGeneratorprops:worker: # SNOWFLAKE算法的worker.idid: 100max: # SNOWFLAKE算法的max.tolerate.time.difference.millisecondstolerate:time:difference:milliseconds: 20datasource:names: ds0,ds1ds0:type: com.alibaba.druid.pool.DruidDataSourcename: testdriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&allowMultiQueries=trueusername: rootpassword: 123456ds1:type: com.alibaba.druid.pool.DruidDataSourcename: test1driverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/test1?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&allowMultiQueries=trueusername: rootpassword: 123456
4. 分片算法类
编写按机构分库算法类:
/*** 按机构精确分片算法类*/
/*** 按机构精确分片算法类*/
@Slf4j
public class DepartPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {@Overridepublic 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 小结
通过分库分表,支持每月千万级数据量问题基本不大。
如果再多,每月上亿、十亿、百亿级别,哈哈,我也不知道啦,因为我还没遇到过。