• Sharding jdbc 强制路由策略(HintShardingStrategy)使用记录


    背景

    随着项目运行时间逐渐增加,数据库中的数据也越来越多,虽然加索引,优化查询,但是数据量太大,还是会影响查询效率,也给数据库增加了负载。
    再加上冷数据基本不使用的场景,决定采用分表来处理数据,从而来提高系统性能。

    sharding jdbc 介绍

    官方文档在这里。
    Sharding-jdbc 定位是轻量级的java框架,在java 的JDBC层提供额外功能。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。

    • 适用于任何基于 java 的ORM 框架(JPA,Hibernate,mybatis 等)
    • 基于任何第三方的数据库连接池(DBCP,c3p0, druid, hikariCP 等)
    • 支持任意实现JDBC规范的数据库(目前支持MySQL,Oracle,SQLServer和PostgreSQL)---因为SQL 语法不同,有对应的解析

    方案选择

    文档很全,并且有三款产品的说明,分别是:Sharding jdbc 、Sharding-proxy、Sharding-sidecar(研发中)
    本着想学技术,先实践写demo的原则,直接跳过SQL,解析引擎,路由、改写、归并引擎等说明,直接到配置界面。
    配置的方式有很多种:

    • java 配置
    • SpringBoot 配置
    • yaml 配置
    • Spring 命名空间配置

    配置好之后,直接传入一个 分片算法即可。

    // 配置数据源
    DataSource getShardingDataSource() throws SQLException {
             ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
             shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
             shardingRuleConfig.getBindingTableGroups().add("t_order");
    // 如果需要打印SQL new Properties 可以 设置一个属性 > io.shardingjdbc.core.constant.ShardingPropertiesConstant#SQL_SHOW
             return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig, new ConcurrentHashMap<>(), new Properties());
         }
        // 针对不同的表可以有不同的策略
         TableRuleConfiguration getOrderTableRuleConfiguration() {
             TableRuleConfiguration result = new TableRuleConfiguration();
             result.setLogicTable("t_order");
             result.setActualDataNodes("ds${0..1}.t_order${0..1}");
             result.setTableShardingStrategyConfig(shardingRuleConfiguration());
             return result;
         }
    
        @Bean
        public ShardingStrategyConfiguration shardingRuleConfiguration() {
            return new MyHintShardingStrategyConfiguration("order_id","com.test.config.MyHintShardingAlgorithm");
        }
     
         Map<String, DataSource> createDataSourceMap() {
             Map<String, DataSource> result = new HashMap<>();
             result.put("ds0", DataSourceUtil.createDataSource("ds0"));
             result.put("ds1", DataSourceUtil.createDataSource("ds1"));
             return result;
         }
    

    踩坑记录

    • 情况
      本来以为这样就可以成功的分片,没想到 MyHintShardingAlgorithm#sharding方法一直都进不去,多次都不行,只能断点调试了。
      确实发现了一个地方:
      见:io.shardingjdbc.core.routing.type.simple.SimpleRoutingEngine#route 方法
    // 分片路由:找到对应的表节点
    @Override
        public RoutingResult route() {
            TableRule tableRule = shardingRule.getTableRule(logicTableName);
            List<ShardingValue> databaseShardingValues = getDatabaseShardingValues(tableRule);
            List<ShardingValue> tableShardingValues = getTableShardingValues(tableRule); // 获取下面表名的地方
            Collection<String> routedDataSources = routeDataSources(tableRule, databaseShardingValues);
            Collection<DataNode> routedDataNodes = new LinkedList<>();
            for (String each : routedDataSources) {
                routedDataNodes.addAll(routeTables(tableRule, each, tableShardingValues));
            }
            return generateRoutingResult(routedDataNodes);
        }
    
    // sharding方法只有这里才会调用,他有一个条件,就是传入的 tableShardingValues 不可以为空
     private Collection<DataNode> routeTables(final TableRule tableRule, final String routedDataSource, final List<ShardingValue> tableShardingValues) {
            Collection<String> availableTargetTables = tableRule.getActualTableNames(routedDataSource);
            Collection<String> routedTables = tableShardingValues.isEmpty() ? availableTargetTables
                    : shardingRule.getTableShardingStrategy(tableRule).doSharding(availableTargetTables, tableShardingValues);// **这里**
            Preconditions.checkState(!routedTables.isEmpty(), "no table route info");
            Collection<DataNode> result = new LinkedList<>();
            for (String each : routedTables) {
                result.add(new DataNode(routedDataSource, each));
            }
            return result;
        }
    // 传入的参数是这里传入的:由于我这里使用强制路由所以走这里
    private List<ShardingValue> getTableShardingValuesFromHint(final Collection<String> shardingColumns) {
            List<ShardingValue> result = new ArrayList<>(shardingColumns.size());
            for (String each : shardingColumns) {
                Optional<ShardingValue> shardingValue = HintManagerHolder.getTableShardingValue(new ShardingKey(logicTableName, each));
                if (shardingValue.isPresent()) {
                    result.add(shardingValue.get());
                }
            }
            return result;
        }
    
    • 分析
      shardingColumns 是从对应的 ShardingStrategy 中赋值的,我使用的强制路由源码如下:
     public HintShardingStrategy(final HintShardingAlgorithm shardingAlgorithm) {
            this.shardingColumns = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
            this.shardingAlgorithm = shardingAlgorithm;
        }
    

    发现shardingColumns 一直是空的,也没有方法可以添加(自定义添加也不行,因为ShardingStrategy是通过对应的ShardingStrategyConfiguration#build方法生成的),所以肯定不会走到路由的地方。

    变更

    排查到这里,就找到了一个修改的方法--重写 ShardingStrategy ,随意给 columns 赋值不为空即可。

    // 自定义新的构造函数,给 shardingColumns 赋值
    public MyHintShardingStrategy(Collection<String> shardingColumns, final HintShardingAlgorithm shardingAlgorithm) {
            this.shardingColumns = new TreeSet<>(shardingColumns);
            this.shardingAlgorithm = shardingAlgorithm;
        }
    

    重新运行项目,发现一切按想要的来。

    回顾

    不知道是自己配置的原因,还是打开的方式不对,反正通过这种方式实现了表的分片。
    向项目提的issue入口在这里,等待回复
    如有不对还请大神们指教!

    **==============20100307更新**
    他们在最新的版本里修复了这个问题,从 HintManageHolder 里获取 sharding Columns。
    代码如下:

    package org.apache.shardingsphere.core.routing.type.standard;
    
    private List<RouteValue> getTableShardingValuesFromHint() {
            return getRouteValues(HintManagerHolder.getTableShardingValues(logicTableName));
        }
    

    但是 mvn 上不知道能不能获取到那个版本,先记录到这里吧。

  • 相关阅读:
    航班查询http://www.variflight.com/
    打印串口日志
    驱动天使 360驱动大师好用2020
    mysqldMY-010457] [Server] --initialize specified but the data directory has files in it. Aborting. 2020-12
    拖拽刻录
    traceroute排查网络故障 www.qq.com排查网络故障网络不通 先ping自己
    tigervnc报错
    java axis调用带有soap头(soapheader)的.net webservice
    java 调用WebService【转】
    List<String>转换为实体类的属性【转】
  • 原文地址:https://www.cnblogs.com/paxing/p/10485204.html
Copyright © 2020-2023  润新知