Sharding jdbc 強制路由策略(HintShardingStrategy)使用記錄
阿新 • • 發佈:2019-03-06
理解 new sim fin columns 時間 隨著 不知道 ring
背景
隨著項目運行時間逐漸增加,數據庫中的數據也越來越多,雖然加索引,優化查詢,但是數據量太大,還是會影響查詢效率,也給數據庫增加了負載。
再加上冷數據基本不使用的場景,決定采用分表來處理數據,從而來提高系統性能。
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入口在這裏,等待回復
如有不對還請大神們指教!
Sharding jdbc 強制路由策略(HintShardingStrategy)使用記錄