背景
隨着項目運行時間逐漸增長,數據庫中的數據也愈來愈多,雖然加索引,優化查詢,可是數據量太大,仍是會影響查詢效率,也給數據庫增長了負載。 再加上冷數據基本不使用的場景,決定採用分表來處理數據,從而來提升系統性能。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 上不知道能不能獲取到那個版本,先記錄到這裏吧。函數