海量数据存储Sharding-JDBC分库分表3

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: 海量数据存储Sharding-JDBC分库分表

8.ShardingJDBC多种分片策略

8.1.Sharding-Jdbc执行流程

  • 长:SQL解析 -> SQL优化 -> SQL路由 -> SQL改写 -> SQL执行 -> 结果归并 ->返回结果
  • 短:解析->路由->改写->执行->结果归并
  • 0db43bed9279405483bad642267e927a.jpg

8.2.精准分片算法《分表》

StandardShardingStrategy(标准分片策略)

  • 只支持【单分片键】,提供PreciseShardingAlgorithmRangeShardingAlgorithm两个分片算法
  • PreciseShardingAlgorithm 精准分片 是必选的,用于处理=和IN的分片
  • RangeShardingAlgorithm 范围分片 是可选的,用于处理BETWEEN AND分片
  • 如果不配置RangeShardingAlgorithm,如果SQL中用了BETWEEN AND语法,则将按照全库路由处理,性能下降

代码案例

@Component
public class CustomTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    /**
     * @param dataSourceNames 数据源集合
     *                        在分库时值为所有分片库的集合 dataSourceNames
     *                        分表时为对应分片库种所有分片表的集合 tableNames
     * @param preciseShardingValue 分片属性
     *                             logicTableName:逻辑表名
     *                             columnName:分片健(字段)
     *                             value:从SQL中解析出的分片健的值
     * @return
     */
    @Override
    public String doSharding(Collection<String> dataSourceNames, PreciseShardingValue<Long> preciseShardingValue) {
        for (String dataSourceName : dataSourceNames) {
            //从preciseShardingValue中拿出分片健,和表的个数取模,确定落在哪个表中
            String value = preciseShardingValue.getValue() % dataSourceNames.size() + "";
            if (dataSourceName.endsWith(value)){
                return dataSourceName;
            }
        }
        throw new IllegalArgumentException();
    }
}

配置文件

spring.application.name=sharding-jdbc
server.port=8080
spring.shardingsphere.props.sql.show=true
# 配置数据源
spring.shardingsphere.datasource.names=ds0,ds1
# 配置ds0库
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://192.168.159.101:3306/shop_order_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds0.product_order_$->{0..1}
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.sharding-column=id
#配置分片策略类的全路径包名
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.precise-algorithm-class-name=com.lixiang.strategy.CustomTablePreciseShardingAlgorithm

测试代码

    @Test
    public void testSaveProductOrder(){
        Random random = new Random();
        for(int i=0;i<10;i++){
            ProductOrderDO productOrder = new ProductOrderDO();
            productOrder.setCreateTime(new Date());
            productOrder.setNickname("李祥:i="+i);
            productOrder.setOutTradeNo(UUID.randomUUID().toString().substring(0,32));
            productOrder.setPayAmount(100.00);
            productOrder.setState("PAY");
            productOrder.setUserId(Long.valueOf(random.nextInt(50)));
            productOrderMapper.insert(productOrder);
        }
    }

fa6345d5b6c141939e83fc2126eca391.jpg

8.3.精准分片算法《分库分表》

新增分库策略类

public class CustomDBPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    /**
     * @param dataSourceNames 数据源集合
     *                        在分库时值为所有分片库的集合 dataSourceNames
     *                        分表时为对应分片库种所有分片表的集合 tableNames
     * @param preciseShardingValue 分片属性
     *                             logicTableName:逻辑表名
     *                             columnName:分片健(字段)
     *                             value:从SQL中解析出的分片健的值
     * @return
     */
    @Override
    public String doSharding(Collection<String> dataSourceNames, PreciseShardingValue<Long> preciseShardingValue) {
        for (String dataSourceName : dataSourceNames) {
            //从preciseShardingValue中拿出分片健,和表的个数取模,确定落在哪个表中
            String value = preciseShardingValue.getValue() % dataSourceNames.size() + "";
            if (dataSourceName.endsWith(value)){
                return dataSourceName;
            }
        }
        throw new IllegalArgumentException();
    }
}

配置文件

spring.application.name=sharding-jdbc
server.port=8080
spring.shardingsphere.props.sql.show=true
# 配置数据源
spring.shardingsphere.datasource.names=ds0,ds1
# 配置ds0库
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://192.168.159.101:3306/shop_order_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
# 配置ds1库
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://192.168.159.101:3306/shop_order_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=123456
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds$->{0..1}.product_order_$->{0..1}
#根据用户id分库
spring.shardingsphere.sharding.tables.product_order.database-strategy.standard.sharding-column=user_id
spring.shardingsphere.sharding.tables.product_order.database-strategy.standard.precise-algorithm-class-name=com.lixiang.strategy.CustomDBPreciseShardingAlgorithm
#根据订单id分表
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.precise-algorithm-class-name=com.lixiang.strategy.CustomTablePreciseShardingAlgorithm

测试代码

    @Test
    public void testSaveProductOrder(){
        Random random = new Random();
        for(int i=0;i<10;i++){
            ProductOrderDO productOrder = new ProductOrderDO();
            productOrder.setCreateTime(new Date());
            productOrder.setNickname("李祥:i="+i);
            productOrder.setOutTradeNo(UUID.randomUUID().toString().substring(0,32));
            productOrder.setPayAmount(100.00);
            productOrder.setState("PAY");
            productOrder.setUserId(Long.valueOf(random.nextInt(50)));
            productOrderMapper.insert(productOrder);
        }
    }

92c36b71ee0b440c891f27d5d523dd53.jpg

8.4.范围分片算法

RangeShardingAlgorithm范围分片

  • 用于处理BETWEEN AND语法,没配置的话会报错Cannot find range sharding strategy in sharding rule。

d09268b3fb30491eb789de36959462c4.jpg

  • 主要是会根据 SQL中给出的分片健值范围值处理分库、分表逻辑。

代码示例

public class CustomRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
    /**
     * @param dataSourceNames 数据源集合
     *                        分库时为所有的库的集合
     *                        分表时为所有的表的集合
     * @param rangeShardingValue 范围分片对象
     *                           logicTableName:逻辑表名
     *                           columnName:分片键名
     *                           valueRange:范围对象,包括lower和upper
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> dataSourceNames, RangeShardingValue<Long> rangeShardingValue) {
        Set<String> result = new LinkedHashSet<>();
        //between 起始值
        Long lower = rangeShardingValue.getValueRange().lowerEndpoint();
        //between 结束值
        Long upper = rangeShardingValue.getValueRange().upperEndpoint();
        //循环范围计算分库逻辑
        for (long i = lower; i <= upper; i++) {
            for (String dataSourceName : dataSourceNames) {
                if(dataSourceName.endsWith(i % dataSourceNames.size() +"")){
                    result.add(dataSourceName);
                }
            }
        }
        return result;
    }
}

配置文件

spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds$->{0..1}.product_order_$->{0..1}
#根据用户id分库
spring.shardingsphere.sharding.tables.product_order.database-strategy.standard.sharding-column=user_id
spring.shardingsphere.sharding.tables.product_order.database-strategy.standard.precise-algorithm-class-name=com.lixiang.strategy.CustomPreciseShardingAlgorithm
#根据订单id分表
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.sharding-column=id
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard.precise-algorithm-class-name=com.lixiang.strategy.CustomPreciseShardingAlgorithm
#根据订单id进行范围分表
spring.shardingsphere.sharding.tables.product_order.table-strategy.standard..range-algorithm-class-name=com.lixiang.strategy.CustomRangeShardingAlgorithm

测试代码

    @Test
    public void testBetweenSelect(){
        productOrderMapper.selectList(new QueryWrapper<ProductOrderDO>().between("id",1L,2L));
    }

8f8abfe3dd294e6bb895c37c99e156ae.jpg

8.5.复合分片算法

复合分片算法ComplexShardingStrategy

  • 提供对SQL语句中的=,in和between and的分片操作,支持【多分片健】
  • 由于多分片键之间的关系复杂,Sharding-JDBC并未做过多的封装
  • 而是直接将分片键值组合以及分片操作符交于算法接口,全部由应用开发者实现,提供最大的灵活度

代码案例

public class CustomComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
    /**
     *
     * @param dataSourceNames 数据源集合
     * @param complexKeysShardingValue 分片属性
     *                                 logicTableName:逻辑表名
     *                                 columnNameAndShardingValuesMap:多分片键集合 <Map<String,Collection<T></>></>></>
     *                                 columnNameAndRangeValuesMap:范围策略,<Map<String,Range<T></>></>></>
     *
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> dataSourceNames, ComplexKeysShardingValue<Long> complexKeysShardingValue) {
        Collection<Long> orderIdValues = this.getShardingValue(complexKeysShardingValue,"id");
        Collection<Long> userIdValues = this.getShardingValue(complexKeysShardingValue,"user_id");
        List<String> shardingSuffix = new ArrayList<>();
        //对两个分片键取模的方式
        for (Long userId : userIdValues) {
            for (Long orderId : orderIdValues) {
                //拼接的效果,0_0,0_1,1_0,1_1,1去匹配product_order_0_0,product_order_0_1,product_order_1_0,product_order_1_1
                String suffix = userId % 2 + "_" + orderId % 2;
                for (String databaseName : dataSourceNames) {
                    if (databaseName.endsWith(suffix)) {
                        shardingSuffix.add(databaseName);
                    }
                }
            }
        }
        return null;
    }
    /**
     *  shardingValues:分片属性
     *  logicTableName:逻辑表
     *  columnNameAndShardingValuesMap 存储多个分片健 包括key-value
     *  value:分片value,66和99
     * @param shardingValues
     * @param key
     * @return
     */
    private Collection<Long> getShardingValue(ComplexKeysShardingValue<Long> shardingValues, String key) {
        Collection<Long> valueSet = new ArrayList<>();
        Map<String, Collection<Long>> columnNameAndShardingValuesMap = shardingValues.getColumnNameAndShardingValuesMap();
        if(columnNameAndShardingValuesMap.containsKey(key)){
            valueSet.addAll(columnNameAndShardingValuesMap.get(key));
        }
        return valueSet;
    }
}

配置文件,记得注释其他策略,否则报错 Only allowed 0 or 1 sharding strategy configuration

#复合分片算法,order_id,user_id 同时作为分片健
spring.shardingsphere.sharding.tables.product_order.table-strategy.complex.sharding-columns=user_id,id
spring.shardingsphere.sharding.tables.product_order.table-strategy.complex.algorithm-class-name=com.lixiang.strategy.CustomComplexKeysShardingAlgorithm

测试代码

    @Test
    public void testComSelect(){
        productOrderMapper.selectList(new QueryWrapper<ProductOrderDO>().eq("id",66L).eq("user_id",99L));
    }

ecef0624af6042ecadd42ff7d9bf03da.jpg

8.6.Hint分片算法

Hint分片策略HintShardingStrategy

  • Hint分片策略无需配置文件进行配置分片健,分片健值也不再从SQL中解析,外部手动去指定分片健或分片库,让SQL在指定的分库、分表中执行。
  • 通过Hint代码指定的方式而非SQL解析的方式分片的策略。
  • Hint策略会绕过SQL解析,对于需要指定库表查询以及一些复杂的分片查询,Hint分片策略新跟那个可能会更好。
  • 可以指定sql去某个库中某个表进行查询。

代码案例

//分库分表共用一个策略
public class CustomHintShardingAlgorithm implements HintShardingAlgorithm<Long> {
    /**
     *
     * @param dataSourceNames 数据源集合
     *                        在分库时值为所有分片库的集合 databaseNames
     *                        分表时为对应分片库中所有分片表的集合 tablesNames
     * @param hintShardingValue 分片属性
     *                          logicTableName:逻辑表
     *                          columnName:分片健(字段),hint策略下为空,""
     *                          value:不在从sql中解析分片的值,而是从
     *                          hintManager.addDatabaseShardingValue("product_order",3L)和
     *                          hintManager.addTableShardingValue("product_order", 8L)中拿值指定数据库,指定表
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> dataSourceNames, HintShardingValue<Long> hintShardingValue) {
        Collection<String> result = new ArrayList<>();
        for (String dataSourceName : dataSourceNames) {
            for (Long value : hintShardingValue.getValues()) {
                if(dataSourceName.endsWith(String.valueOf(value % dataSourceNames.size()))){
                    result.add(dataSourceName);
                }
            }
        }
        return result;
    }
}

配置文件

spring.application.name=sharding-jdbc
server.port=8080
spring.shardingsphere.props.sql.show=true
# 配置数据源
spring.shardingsphere.datasource.names=ds0,ds1
# 配置ds0库
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://192.168.159.101:3306/shop_order_0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456
# 配置ds1库
spring.shardingsphere.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.ds1.jdbc-url=jdbc:mysql://192.168.159.101:3306/shop_order_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.shardingsphere.datasource.ds1.username=root
spring.shardingsphere.datasource.ds1.password=123456
spring.shardingsphere.sharding.tables.product_order.key-generator.column=id
spring.shardingsphere.sharding.tables.product_order.key-generator.type=SNOWFLAKE
spring.shardingsphere.sharding.tables.product_order.actual-data-nodes=ds$->{0..1}.product_order_$->{0..1}
#Hint 分片算法
spring.shardingsphere.sharding.tables.product_order.table-strategy.hint.algorithm-class-name=com.lixiang.strategy.CustomHintShardingAlgorithm
spring.shardingsphere.sharding.tables.product_order.database-strategy.hint.algorithm-class-name=com.lixiang.strategy.CustomHintShardingAlgorithm

测试代码

 /**
     * HintManger可以配合AOP切面
     */
    @Test
    public void testHint(){
        //清除掉历史的规则
        HintManager.clear();
        //Hint分片策略必须使用HintManager工具类
        HintManager hintManager = HintManager.getInstance();
        //设置库的分片健,value用于表分片取模
        hintManager.addDatabaseShardingValue("product_order",3L);
        //设置表的分片健,value用于表分片健
        hintManager.addTableShardingValue("product_order",8L);
        //如果在读写分离数据库中,Hint可以强制读主库(主从复制存在一定的延迟)
        //hintManager.setMasterRouteOnly();
        //对应的value只做查询,不做sql解析
        productOrderMapper.selectList(new QueryWrapper<ProductOrderDO>().eq("id", 66L));
    }


7dd9feb601804704abf71ec90f33a454.jpg

8.7.多种分片策略总结

  • 自定义分片策略的优缺点
  • 优点:可以根据分片策略代码里面自己拼接真实的数据库、真实的表,灵活控制分片规则。
  • 缺点:增加了编码,不规范的sql容易造成全库表扫描,部分sql语法支持不友好。
  • 行表达式分片策略InlineShardingStrategy
  • 只支持【单分片键】使用Groovy的表达式,提供对SQL语句中的=和IN的分片操作支持。
  • 可以通过简单的配置使用,无需自定义分片算法,从而避免繁琐的Java代码开发
product_order_$->{user_id % 8}表示订单表根据user_id模8,而分成8张表,表名称为`prouduct_order_0`到`prouduct_order_7

标准分片策略StandardShardingStrategy

  • 只支持【单分片健】,提供PreciseShardingAlgorithm和RangeShardingAlgorithm两个分片算法。
  • PreciseShardingAlgorithm精准分片 是必选的,用于处理=和IN的分片。
  • RangeShardingAlgorithm范围分片 是可选的,用于处理BETWEEN AND分片。
  • 如果不配置RangeShardingAlgorithm,如果SQL中用了BETWEEN AND语法,则将按照全库路由处理,性能下降。
  • 复合分片策略ComplexShardingStrategy
  • 支持【多分片键】,多分片键之间的关系复杂,由开发者自己实现,提供最大的灵活度。
  • 提供对SQL语句中的=, IN和BETWEEN AND的分片操作支持。
  • Hint分片策略HintShardingStrategy
  • 这种分片策略无需配置分片健,分片健值也不再从 SQL中解析,外部手动指定分片健或分片库,让 SQL在指定的分库、分表中执行。
  • 用于处理使用Hint行分片的场景,通过Hint而非SQL解析的方式分片的策略。

  • Hint策略会绕过SQL解析的,对于这些比较复杂的需要分片的查询,Hint分片策略性能可能会更好。

9.分库分表常见问题

9.1.分库分表已解决的三大问题

问题一:执行SQL排序、翻页、函数计算问题

  • 分库后,数据分布再不同的节点上, 跨节点多库进行查询时,会出现limit分页、order by排序等问题。
  • 而且当排序字段非分片字段时,更加复杂了,要在不同的分片节点中将数据进行排序并返回,然后将不同分片返回的结果集进行汇总和再次排序(也会带来更多的CPU/IO资源损耗)。
  • 解决方式:
  • 业务上要设计合理,利用好PartitionKey,查询的数据分布同个数据节点上,避免 跨节点多库进行查询时。
  • sharding-jdbc在结果合并层自动帮我们解决很多问题(流式归并和内存归并)。
  • 问题二:数据库全局主键重复问题
  • 常规表的id是使用自增id进行实现,分库分表后,由于表中数据同时存在不同数据库中,如果用自增id,则会出现冲突问题
  • 解决方式:
  • UUID
  • 自研发号器 redis
  • 雪花算法

问题三:分库分表技术选型问题

  • 市场分库分表中间件相对较多,框架各有各的优势与短板,应该如何选择
  • 解决方式
  • 开源产品:主要是Mycat和ShardingJdbc区别,也是被面试官问比较多的
  • 两者设计理念相同,主流程都是SQL解析–>SQL路由–>SQL改写–>结果归并
  • sharding-jdbc(推荐
  • 基于jdbc驱动,不用额外的proxy,在本地应用层重写Jdbc原生的方法,实现数据库分片形式
  • 是基于 JDBC 接口的扩展,是以 jar 包的形式提供轻量级服务的,性能高
  • 代码有侵入性
  • Mycat
  • 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库
  • 客户端所有的jdbc请求都必须要先交给MyCat,再有MyCat转发到具体的真实服务器
  • 缺点是效率偏低,中间包装了一层
  • 代码无侵入性

9.2.跨节点数据库复杂查询

  • 数据库切分前,多表关联查询,可以通过sql join进行实现
  • 分库分表后,数据可能分布在不同的节点上,sql join带来的问题就比较麻烦
  • 不同维度查看数据,利用的partitionKey是不一样的
  • 解决方案
  • 冗余字段
  • 广播表
  • NOSQL汇总
  • 案例一
  • 订单需要用户的基本信息,但是分布在不同库上
  • 进行字段冗余,订单表冗余用户昵称、头像
  • 案例二
  • 订单表 的partionKey是user_id,用户查看自己的订单列表方便
  • 但商家查看自己店铺的订单列表就麻烦,分布在不同数据节点
  • 订单冗余存储在es上一份
  • 业务架构流程

cec375d1c675457b8edc5d8c24044249.jpg

9.3.分库分表分布式事务问题

问题:分库操作带来的分布式事务问题

  • 操作内容同时分布在不同库中,不可避免会带来跨库事务问题,即分布式事务

常见分布式事务解决方案

  • 2PC 和 3PC
  • 两阶段提交, 基于XA协议
  • TCC
  • Try、Confirm、Cancel
  • 事务消息
  • 最大努力通知型

分布式事务框架

  • X-LCN:支持2PC、TCC等多种模式
  • Seata:支持 AT、TCC、SAGA 和 XA 多种模式
  • RocketMq:自带事务消息解决分布式事务
  • MQ+本地Task
  • 定时任务

9.4.分库分表后二次扩容问题

问题:容量规划,分库分表后二次扩容问题

  • 业务发展快,初次分库分表后,满足不了数据存储,导致需要多次扩容,数据迁移问题
  • 取决是哪种分库分表规则
  • Range范围
  • 时间:不用考虑扩容迁移
  • 区域:调整分片粒度,需要全量迁移
  • Hash取模
  • 业务最多的是hash取模分片,因扩分库分表涉及到rehash过程
  • 分片数量建议可以成倍扩容策略,只需要【迁移部分数据】即可
  • 旧节点的数据,有一半要迁移至一个新增节点中


a8bda0e0d08c40549fec6201d858b1e6.jpg解决方式

方式一:利用主从同步


6c22d38d827c4f7883f927157b18bf3e.jpg

  • 新增两个数据库 A2、A3 作为从库,设置主从同步关系为:A0=>A2、A1=>A3,
  • 开启主从数据同步,早期数据手工同步过去
  • 发布新程序,某个时间点开始,利用MQ存储CUD操作
  • 关闭数据库实例的主从同步关系
  • 校验数据,消费原先MQ存储CUD操作,配置新分片规则和生效

数据校验和修复

  • 依赖gmt_modified字段,所以常规数据表都需要加这个字段
  • 由数据库自己维护值,根据业务场景,进行修复对应的数据
  • 校验步骤
  • 开始迁移时间假如是2022-01-01 00:00:00
  • 查找 gmt_modified数据校验修复大于开始时间点,就是修改过的数据
  • 各个节点的冗余数据进行删除
  • 缺点
  • 同步的很多数据到最后都需要被删除
  • 一定要提前做,越晚做成本越高,因为扩容期间需要存储的数据更多
  • 基本都离不开代码侵入,加锁等操作
  • 优点
  • 利用mysql自带的主从同步能力
  • 方案简单,代码量相对少

方式二:停服务

  • 对外发布公告,停机迁移
  • 严格一致性要求:比如证券、银行部分数据等
  • 优点:最方便、且安全
  • 缺点
  • 会造成服务不可用,影响业务
  • 根据停机的时间段,数据校验人员有压力
    户查看自己的订单列表方便
  • 但商家查看自己店铺的订单列表就麻烦,分布在不同数据节点
  • 订单冗余存储在es上一份
  • 业务架构流程


相关文章
|
1月前
|
存储 弹性计算 中间件
|
1月前
|
Java
SpringBoot整合sharding-jdbc实现分库分表
SpringBoot整合sharding-jdbc实现分库分表
70 1
|
7月前
|
SQL Java 中间件
Springboot集成 Sharding-JDBC + Mybatis-Plus实现分库分表(源码)
Sharding-jdbc是开源的数据库操作中间件;定位为轻量级Java框架,在Java的JDBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
|
11月前
|
存储 数据库
MYSQLg高级-------分库分表之核心Sharding-JDBC(三)
MYSQLg高级-------分库分表之核心Sharding-JDBC(三)
68 0
|
11月前
|
Java 数据库
MYSQLg高级-------分库分表之核心Sharding-JDBC(二)
MYSQLg高级-------分库分表之核心Sharding-JDBC(二)
83 0
|
11月前
|
算法 druid Java
MYSQLg高级-------分库分表之核心Sharding-JDBC(一)
MYSQLg高级-------分库分表之核心Sharding-JDBC(一)
144 0
|
SQL 存储 算法
聊聊 Sharding-JDBC 分库分表
聊聊 Sharding-JDBC 分库分表
|
SQL 存储 算法
海量数据存储Sharding-JDBC分库分表2
海量数据存储Sharding-JDBC分库分表
|
SQL 存储 算法
海量数据存储Sharding-JDBC分库分表1
海量数据存储Sharding-JDBC分库分表
|
1月前
|
Java 关系型数据库 数据库连接
实时计算 Flink版操作报错之在使用JDBC连接MySQL数据库时遇到报错,识别不到jdbc了,怎么解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。