Sharding-JDBC基礎概念及API操作

  在分佈式服務中,要實現數據源得選擇有如下相關方案

  • DAO:繼承  AbstractRoutingDataSource 類,實現對應的切換數據源的方法,結合自定義註解 + 切面實現動態數據源切換。
  • ORM:MyBatis 插件進行數據源切換
  • JDBC:Sharding-JDBC 基於客戶端的分庫分表方案
  • Proxy:Mycat、Sharding-Proxy 基於代理的分庫分表方案
  • Server:特定數據庫或者版本
  • .........

基本概念及架構:

  Sharding JDBC 是從噹噹網的內部架構 ddframe 裏面的一個分庫分表的模塊脫胎出來的,用來解決噹噹的分庫分表的問題,把跟業務相關的敏感的代碼剝離後,就得到了 Sharding-JDBC。它是一個工作在客戶端的分庫分表的解決方案。

  DubboX,Elastic-job 也是噹噹開源出來的產品。

  2018 年 5 月,因爲增加了 Proxy 的版本和 Sharding-Sidecar(尚未發佈),Sharding-JDBC 更名爲 Sharding Sphere,從一個客戶端的組件變成了一個套件。

  2018 年 11 月,Sharding-Sphere 正式進入 Apache 基金會孵化器,這也是對Sharding-Sphere 的質量和影響力的認可。不過現在還沒有畢業(名字帶 incubator),

  一般我們用的還是 io.shardingsphere 的包。因爲更名後和捐獻給 Apache 之後的 groupId 都不一樣,在引入依賴的時候千萬要注意。主體功能是相同的,但是在某些類的用法上有些差異,如果要升級的話 import 要全部修改,有些類和方法也要修改。

  定位爲輕量級Java框架,在Java的JDBC層提供的額外服務。 它使用客戶端直連數據庫,以jar包形式提供服務,無需額外部署和依賴,可理解爲增強版的JDBC驅動,完全兼容JDBC和各種ORM框架。

  • 適用於任何基於JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 支持任何第三方的數據庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意實現JDBC規範的數據庫。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92標準的數據庫。

  在 maven 的工程裏面,我們使用它的方式是引入依賴,然後進行配置就可以了,不用像 Mycat 一樣獨立運行一個服務,客戶端不需要修改任何一行代碼,原來是 SSM 連接數據庫,還是 SSM,因爲它是支持 MyBatis 的。

  我們在項目內引入 Sharding-JDBC 的依賴,我們的業務代碼在操作數據庫的時候,就會通過 Sharding-JDBC 的代碼連接到數據庫。分庫分表的一些核心動作,比如 SQL 解析,路由,執行,結果處理,都是由它來完成的。它工作在客戶端。

  在 Sharding-Sphere 裏面同樣提供了代理 Proxy 的版本,跟 Mycat 的作用是一樣的。Sharding-Sidecar 是一個 Kubernetes 的雲原生數據庫代理,正在開發中。

核心功能 :

  分庫分表後的幾大問題:跨庫關聯查詢、分佈式事務、排序翻頁計算、全局主鍵。

  數據分片

  1. 分庫 & 分表
  2. 讀寫分離:https://shardingsphere.apache.org/document/current/cn/features/read-write-split/
  3. 分片策略定製化
  4. 無中心化分佈式主鍵(包括 UUID、雪花、LEAF)

  分佈式事務:https://shardingsphere.apache.org/document/current/cn/features/transaction/

  1. 標準化事務接口
  2. XA 強一致事務
  3. 柔性事務

核心概念:

  • 邏輯表:水平拆分的數據庫(表)的相同邏輯和數據結構表的總稱。例:訂單數據根據主鍵尾數拆分爲 10 張表,分別是 t_order_0 到 t_order_9,他們的邏輯表名爲 t_order
  • 真實表:在分片的數據庫中真實存在的物理表。即上個示例中的 t_order_0 到 t_order_9
  • 數據節點:數據分片的最小單元。由數據源名稱和數據表組成,例:ds_0.t_order_0
  • 綁定表:指分片規則一致的主表和子表。例如:t_order 表和 t_order_item 表,均按照 order_id 分片,則此兩張表互爲綁定表關係。綁定表之間的多表關聯查詢不會出現笛卡爾積關聯,關聯查詢效率將大大提升。
  • 廣播表:指所有的分片數據源中都存在的表,表結構和表中的數據在每個數據庫中均完全一致。適用於數據量不大且需要與海量數據的表進行關聯查詢的場景,例如:字典表。
  • 分片鍵:根據指定的分片鍵進行路由。分片鍵不一定是主鍵,也不一定有業務含義。

使用規範 :

  雖然 Apache ShardingSphere 希望能夠完全兼容所有的SQL以及單機數據庫,但分佈式爲數據庫帶來了更加複雜的場景。包括一些特殊的 sql 或者分頁都帶來了巨大的挑戰。對於這方面sharding-jdbc也做出了相關的說明

  https://shardingsphere.apache.org/document/current/cn/features/sharding/use-norms/

與 Mycat 對比 :

  Sharding-JDBC  Mycat
工作 層面 JDBC 協議 MySQL 協議/JDBC 協議
運行方式 Jar 包,客戶端   獨立服務,服務端
開發 方式 代碼/配置改動 連接地址(數據源)
運維 方式  管理獨立服務,運維成本高
性能 多線程併發按操作,性能高 獨立服務+網絡開銷,存在性能損失風險
功能 範圍 協議層面  包括分佈式事務、數據遷移等
適用 操作 OLTP  OLTP+OLAP
支持 數據庫 基於 JDBC 協議的數據庫 MySQL 和其他支持 JDBC 協議的數據庫
支持 語言 Java 項目中使用  支持 JDBC 協議的語言
維度 二維,支持分庫又分表,比如user表繼續拆分爲user1、user2 一維,分了庫後表不可以繼續拆分,或者單庫分表

 


  

  

  

 
  
 

 

 

 

  

 

  

  從易用性和功能完善的角度來說,Mycat 似乎比 Sharding-JDBC 要好,因爲有現成的分片規則,也提供了 4 種 ID 生成方式,通過註解可以支持高級功能,比如跨庫關聯查詢。

  建議:小型項目,分片規則簡單的項目可以用 Sharding-JDBC。大型項目,可以用Mycat。

Sharding-JDBC 案例 :

  Sharding-JDBC要實現分庫分表的方案主要分爲以下幾個步驟:

  1. 配置數據源。
  2. 配置表規則 TableRuleConfiguration。
  3. 配置分庫+分表策略 DatabaseShardingStrategyConfig,TableShardingStrategyConfig。
  4. 獲取數據源對象。
  5. 執行數據庫操作。

1.首先我們創建一個標準的springboot工程。還需要引入相關依賴:

<dependencies>
        <!--sharding-jdbc -->
        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

2.編寫類 :

 1 public class ShardJDBCTest {
 2     public static void main(String[] args) throws SQLException {
 3         // 1. 配置真實數據源
 4         Map<String, DataSource> dataSourceMap = new HashMap<>();
 5 
 6         // 配置第一個數據源
 7         DruidDataSource dataSource1 = new DruidDataSource();
 8         dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
 9         dataSource1.setUrl("jdbc:mysql://192.168.1.101:3306/shard0");
10         dataSource1.setUsername("root");
11         dataSource1.setPassword("123456");
12         dataSourceMap.put("ds0", dataSource1);
13 
14         // 配置第二個數據源
15         DruidDataSource dataSource2 = new DruidDataSource();
16         dataSource2.setDriverClassName("com.mysql.jdbc.Driver");
17         dataSource2.setUrl("jdbc:mysql://192.168.1.104:3306/shard1");
18         dataSource2.setUsername("root");
19         dataSource2.setPassword("123456");
20         dataSourceMap.put("ds1", dataSource2);
21 
22         // 2. 配置Order表規則
23         TableRuleConfiguration orderTableRuleConfig = new TableRuleConfiguration();
24         orderTableRuleConfig.setLogicTable("order");
25         orderTableRuleConfig.setActualDataNodes("ds${0..1}.order${0..1}");
26 
27 
28         // 3. 配置分庫 + 分表策略
29         orderTableRuleConfig.setDatabaseShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "ds${order_id % 2}"));
30         orderTableRuleConfig.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "order${order_id % 2}"));
31 
32         // 配置分片規則
33         ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
34         shardingRuleConfig.getTableRuleConfigs().add(orderTableRuleConfig);
35 
36         Map<String, Object> map = new HashMap<>();
37 
38         // 4.獲取數據源對象
39         DataSource dataSource = ShardingDataSourceFactory.createDataSource(dataSourceMap, shardingRuleConfig, map, new Properties());
40 
41         String sql = "SELECT * from order WHERE user_id=?";
42         try (
43                 Connection conn = dataSource.getConnection();
44                 PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
45             preparedStatement.setInt(1, 2673);
46             System.out.println();
47             // 5.執行sql
48             try (ResultSet rs = preparedStatement.executeQuery()) {
49                 while (rs.next()) {
50                     // %2結果,路由到 shard1.order1
51                     System.out.println("order_id---------" + rs.getInt(1));
52                     System.out.println("user_id---------" + rs.getInt(2));
53                     System.out.println("create_time---------" + rs.getTime(3));
54                     System.out.println("total_price---------" + rs.getInt(4));
55                 }
56             }
57         }
58     }
59 }

3.在兩個庫上都建立對應的 order1、order2 表,表結構一致。字段自己調整就行

  運行上述main方法可以查看到相應的效果。

  總結:ShardingRuleConfiguration 可以包含多個 TableRuleConfiguration(多張表),也可以設置默認的分庫和分表策略。每個 TableRuleConfiguration 可以針對表設置 ShardingStrategyConfiguration,包括分庫分分表策略。

  ShardingStrategyConfiguration 有 5 種實現(標準、行內、複合、Hint、無)。ShardingDataSourceFactory 利用 ShardingRuleConfiguration 創建數據源。有了數據源,就可以走 JDBC 的流程了。

  更多配置可以參考 https://shardingsphere.apache.org/document/current/cn/user-manual/shardingsphere-jdbc/configuration/

整合SpringBoot :

  Sharding-JDBC 進行與 SpringBoot 的整合是方便的,主要是進行配置文件的配置。

1.創建標準的SpringBoot 工程,再加入以下依賴:

<dependencies>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

        <!--xa分佈式事務-->
        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-transaction-2pc-xa</artifactId>
            <version>3.1.0</version>
        </dependency>

        <dependency>
            <groupId>io.shardingsphere</groupId>
            <artifactId>sharding-transaction-spring-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>

2.進行 分庫分表規則配置,新建 application-sharding.yml 文件 :

sharding:
  jdbc:
    datasource:
      # 數據源
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.1.101:3306/shard0
        username: root
        password: 123456
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://192.168.1.104:3306/shard1
        username: root
        password: 123456
    config:
      sharding:
        # 默認數據源,不分庫分表到達這個數據源
        default-data-source-name: ds0
        #【默認分庫策略】對user_id取模
        default-database-strategy:
          inline:
            sharding-column: user_id
            algorithm-expression: ds$->{user_id % 2}
        # 【分表策略】
        tables:
          # dictionary是廣播表
          dictionary:
            key-generator-column-name: dictionary_id
            actual-data-nodes: ds$->{0..1}.dictionary
          # user表只分庫不分表
          user:
            key-generator-column-name: user_id
            actual-data-nodes: ds$->{0..1}.user
          # order表分庫分表
          order:
            key-generator-column-name: order_id
            actual-data-nodes: ds$->{0..1}.order$->{0..1}
            table-strategy:
              inline:
                sharding-column: order_id
                algorithm-expression: order$->{order_id%2}
          # order_item表分庫分表
          order_item:
            key-generator-column-name: order_item_id
            actual-data-nodes: ds$->{0..1}.order_item$->{0..1}
            table-strategy:
              inline:
                sharding-column: order_id
                algorithm-expression: order_item$->{order_id%2}
      props:
        sql.show: true

3.其他關於 mybatis 的相關配置這裏就不貼出來了。然後在數據庫中創建對應的表。編寫 dao、service 進行測試。關於事務、全局ID、自定義分片策略下篇博客中會詳細介紹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章