Sharding jdbc 強制路由策略(HintShardingStrategy)使用記錄

背景

隨着項目運行時間逐漸增長,數據庫中的數據也愈來愈多,雖然加索引,優化查詢,可是數據量太大,仍是會影響查詢效率,也給數據庫增長了負載。 再加上冷數據基本不使用的場景,決定採用分表來處理數據,從而來提升系統性能。java

sharding jdbc 介紹

官方文檔在這裏。 Sharding-jdbc 定位是輕量級的java框架,在java 的JDBC層提供額外功能。它使用客戶端直連數據庫,以jar包形式提供服務,無需額外部署和依賴,可理解爲加強版的JDBC驅動,徹底兼容JDBC和各類ORM框架。git

  • 適用於任何基於 java 的ORM 框架(JPA,Hibernate,mybatis 等)
  • 基於任何第三方的數據庫鏈接池(DBCP,c3p0, druid, hikariCP 等)
  • 支持任意實現JDBC規範的數據庫(目前支持MySQL,Oracle,SQLServer和PostgreSQL)---由於SQL 語法不一樣,有對應的解析

方案選擇

文檔很全,而且有三款產品的說明,分別是:Sharding jdbc 、Sharding-proxy、Sharding-sidecar(研發中) 本着想學技術,先實踐寫demo的原則,直接跳過SQL,解析引擎,路由、改寫、歸併引擎等說明,直接到配置界面。 配置的方式有不少種:github

  • 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 賦值不爲空便可。apache

// 自定義新的構造函數,給 shardingColumns 賦值
public MyHintShardingStrategy(Collection<String> shardingColumns, final HintShardingAlgorithm shardingAlgorithm) {
        this.shardingColumns = new TreeSet<>(shardingColumns);
        this.shardingAlgorithm = shardingAlgorithm;
    }

從新運行項目,發現一切按想要的來。mybatis

回顧

不知道是本身配置的緣由,仍是打開的方式不對,反正經過這種方式實現了表的分片。 向項目提的issue入口在這裏,等待回覆 若有不對還請大神們指教!框架

==============20100307更新 他們在最新的版本里修復了這個問題,從 HintManageHolder 裏獲取 sharding Columns。 代碼以下:ide

package org.apache.shardingsphere.core.routing.type.standard;

private List<RouteValue> getTableShardingValuesFromHint() {
        return getRouteValues(HintManagerHolder.getTableShardingValues(logicTableName));
    }

可是 mvn 上不知道能不能獲取到那個版本,先記錄到這裏吧。函數

相關文章
相關標籤/搜索