SpringBoot使用shardingsphere实现分表

一、为什么需要分库分表?

由于数据库的承载能力是有限的,当业务增长量达到一定规模后,数据库的性能就会达到瓶颈。就拿使用最多的 MySQL 来进行说明。

MySQL 的默认引擎是 InnoDB,数据是存在聚簇索引中,而聚簇索引的底层数据结构是 B+ Tree,即使 B+Tree 已经在 B Tree 的基础上优化了空间利用率,但是随着数据规模的增大,树的高度也会达到一定规模,高度能够决定磁盘IO的次数,磁盘IO次数越多,对于性能就会越低。

二、数据库多大才推荐分库分表?

根据阿里开发手册中描述,单表超 500 万行或容量超 2GB 时推荐分库分表。但是具体的情况还是需要根据业务需求、数据库硬件配置、CPU 性能等方面综合评估。

除此之外,要想详细的估算出数据量的瓶颈,还需要根据表的结构以及索引情况,表的字段不同的类型占用的大小也不同,故每条数据占用的大小也不同, B+Tree 每一层的存储数据量的大小也会发生变化。

综上,数据量多大需要根据自身情况去评估,并不一定是网上所说的 1000 万,也不一定是阿里所说的大于 500 万,这就是有些企业单表数据即使超过几千万仍可稳定运行的原因。

三、如何实现分库分表?

3.1 垂直分表

垂直分表指将存在一张表中的不同字段拆分为多张表,是一种大表拆小表的模式。拆分后的表字段、结构均不同,组合一起则是原表。

一般是将经常修改的、数据较大的、不常查询的字段拆分到“扩展表”中,这样拆分以后核心表大多是访问频率较高的字段,而且字段长度也都较短,减少了查询时的磁盘 IO,提升数据库效率

3.2 水平分表

水平分库是将数据库中的表数据按照某种规则拆分到多个库中,以实现水平扩展,提升数据库读写性能。

一般切分到不同的库中的表结构是相同的,表中数据不同,且伴随水平分表。

3.3 实现垂直分表

讲述完分表概念后咱们就动手实现了,本文着重讲述下怎么实现垂直分表,对水平分表感兴趣的伙伴们也可后台留言,下期讲述如何手把手实现水平分表

3.3.1 pom引入shardingsphere依赖

<!-- ShardingSphere JDBC Starter -->
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.0.0-RC1</version>
</dependency>
<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-namespace</artifactId>
    <version>4.0.0-RC1</version>
</dependency>

3.3.2 配置分片策略

StandardPreciseDateTimeShardingAlgorithmConfig.class
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.springframework.stereotype.Component;

import java.util.Collection;

/**
 * @author Larkin.Long
 * @description 根据单个指定时间字段分片策略
 * @date 2024/6/7 12:44
 **/
@Component
public class StandardPreciseDateTimeShardingAlgorithmConfig implements PreciseShardingAlgorithm {
    @Override
    public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) {
        String tableNamePrefix = preciseShardingValue.getLogicTableName();
        return tableNamePrefix+"_"+preciseShardingValue.getValue();
    }
}

StandardRangeDateTimeShardingAlgorithmConfig.class
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * @author Larkin.Long
 * @description 根据时间范围分片
 * @date 2024/6/7 12:42
 **/
@Component
public class StandardRangeDateTimeShardingAlgorithmConfig implements RangeShardingAlgorithm {

    @Override
    public Collection<String> doSharding(Collection collection, RangeShardingValue rangeShardingValue) {
        String tableName = rangeShardingValue.getLogicTableName();
        Set<String> set = new HashSet<>();
        Range rangeValue = rangeShardingValue.getValueRange();
        if (rangeValue.hasUpperBound() && rangeValue.hasLowerBound()) {
            String minValue = String.valueOf(rangeValue.lowerEndpoint());
            String maxValue = String.valueOf(rangeValue.upperEndpoint());
            long range = DateUtil.between(DateUtil.parse(minValue, DatePattern.PURE_DATE_PATTERN), DateUtil.parse(maxValue, DatePattern.PURE_DATE_PATTERN), DateUnit.DAY);
            for (int i = 0; i <= range; i++) {
                set.add(tableName+"_"+DateUtil.format(DateUtil.offsetDay(DateUtil.parse(minValue, DatePattern.PURE_DATE_PATTERN),i),DatePattern.PURE_DATE_PATTERN));
            }
        }
        return set;
    }

}

3.3.3 yml配置垂直分表

  shardingsphere:
    datasource:
      names: ds0
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: org.postgresql.Driver
        url: jdbc:postgresql://127.0.0.1:9011/console?useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
        username: postgres
        password: console1234
    sharding:
      tables:
        rc_calllog_total:
          actual-data-nodes: ds0.rc_calllog_total_$->{0..0}
          table-strategy:
            standard:
              sharding-column: date_time
              precise-algorithm-class-name: com.rainnytech.dataapi.common.standard.StandardPreciseDateTimeShardingAlgorithmConfig
              range-algorithm-class-name: com.rainnytech.dataapi.common.standard.StandardRangeDateTimeShardingAlgorithmConfig
    props:
      sql:
        show: true
shardingsphere需要配置在spring层级下
datasource:定义需要实现分表的数据源
sharding:定义需要走分表策略的表(其中
sharding-column对应所需分表的表中依赖字段
props:定义是否开启sql日志打印
sharding-column

3.3.4 定义需要分的表(如下图)

这里我是按月实现分表,伙伴们也可根据现实业务需要定义按年还是月进行分表

表结构必须包含刚才我们yml定义的分表字段,即sharding-column对应的字段

3.3.5 验证分表

启动项目,写个接口查询我们的分表,查看sql打印日志,已经成功查询我们需要查询的表

好了,今天的垂直分表就完成了

四、特别注意!!!

date_time为我们的分表依据,举个例子,当我们想查询3月份里面的数据,查询条件必须包含date_time = 202403,CRUD同理,当date_time参数值为几月份时就查询几月份的表数据,只要涉及到我们配置的表,sql语句都需要添加date_time条件!!!伙伴们一定要注意!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值