1. 程式人生 > >噹噹分庫分表中介軟體-sharding-jdbc

噹噹分庫分表中介軟體-sharding-jdbc

使用指南

閱讀本指南前,請先閱讀快速起步。本文件使用更復雜的場景進一步介紹Sharding-JDBC的分庫分表能力。

資料庫模式

本文件中提供了兩個資料來源db0db1,每個資料來源之中包含了兩組表t_order_0t_order_1t_order_item_0t_order_item_1。這兩組表的建表語句為:

CREATE TABLE IF NOT EXISTS `t_order_x` (
  `order_id` INT NOT NULL,
  `user_id`  INT NOT NULL,
  PRIMARY KEY (`order_id`)
);
CREATE TABLE
IF NOT EXISTS `t_order_item_x` ( `item_id` INT NOT NULL, `order_id` INT NOT NULL, `user_id` INT NOT NULL, PRIMARY KEY (`item_id`) );

邏輯表與實際表對映關係

均勻分佈

資料表在每個資料來源內呈現均勻分佈的態勢

db0
  ├── t_order_0 
  └── t_order_1 
db1
  ├── t_order_0 
  └── t_order_1

表規則可以使用預設的配置

 TableRule orderTableRule =
new TableRule("t_order", Arrays.asList("t_order_0", "t_order_1"), dataSourceRule);

自定義分佈

資料表呈現有特定規則的分佈

db0
  ├── t_order_0 
  └── t_order_1 
db1
  ├── t_order_2
  ├── t_order_3
  └── t_order_4

表規則可以指定每張表在資料來源中的分佈情況

 TableRule orderTableRule = new TableRule("t_order", Arrays.asList("db0.t_order_0", "db0.t_order_1"
, "db1.t_order_2", "db1.t_order_3", "db1.t_order_4"), dataSourceRule);

本教程採用的資料分佈例子

db0
  ├── t_order_0               user_id為偶數   order_id為偶數
  ├── t_order_1               user_id為偶數   order_id為奇數
  ├── t_order_item_0          user_id為偶數   order_id為偶數
  └── t_order_item_1          user_id為偶數   order_id為奇數
db1
  ├── t_order_0               user_id為奇數   order_id為偶數
  ├── t_order_1               user_id為奇數   order_id為奇數
  ├── t_order_item_0          user_id為奇數   order_id為偶數
  └── t_order_item_1          user_id為奇數   order_id為奇數

邏輯表與實際表

配置分庫分表的目的是將原有一張表的資料分散到不同庫不同表中,且不改變原有SQL語句的情況下來使用這一張表。那麼從一張表到多張的對映關係需要使用邏輯表與實際表這兩種概念。下面通過一個例子來解釋一下。假設在使用PreparedStatement訪問資料庫,SQL如下:

select * from t_order where user_id = ? and order_id = ?;

user_id=0order=0時,Sharding-JDBC將會將SQL語句轉換為如下形式:

select * from db0.t_order_0 where user_id = ? and order_id = ?;

其中原始SQL中的t_order就是 邏輯表,而轉換後的db0.t_order_0就是 實際表

規則配置

以上分庫分表的形式Sharding-JDBC是通過規則配置來進行的描述的,下面講通過幾個小節來描述規則的詳細配置:

 ShardingRule shardingRule = new ShardingRule(dataSourceRule, Arrays.asList(orderTableRule, orderItemTableRule),
                Arrays.asList(new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule))),
                new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()),
                new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()));

資料來源配置

首先我們來構造DataSourceRule物件,它是來描述資料來源的分佈規則的。

 DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap);

這裡構造器需要一個入參:資料來源名稱與真實資料來源之間的對映關係,這個關係的構造方法如下

Map<String, DataSource> dataSourceMap = new HashMap<>(2);
dataSourceMap.put("ds_0", createDataSource("ds_0"));
dataSourceMap.put("ds_1", createDataSource("ds_1"));

真實的資料來源可以使用任意一種資料庫連線池,這裡使用DBCP來舉例

private static DataSource createDataSource(final String dataSourceName) {
    BasicDataSource result = new BasicDataSource();
    result.setDriverClassName(com.mysql.jdbc.Driver.class.getName());
    result.setUrl(String.format("jdbc:mysql://localhost:3306/%s", dataSourceName));
    result.setUsername("root");
    result.setPassword("");
    return result;
}

策略配置

資料來源策略與表策略

策略類圖 Sharding-JDBC認為對於分片策略存有兩種維度 - 資料來源分片策略DatabaseShardingStrategy:資料被分配的目標資料來源 - 表分片策略TableShardingStrategy:資料被分配的目標表,該目標表存在與該資料的目標資料來源內。故表分片策略是依賴與資料來源分片策略的結果的 這裡注意的是兩種策略的API完全相同,以下針對策略API的講解將適用於這兩種策略

全域性預設策略與特定表策略

策略是作用在特定的表規則上的,資料來源策略與表策略與特定表相關

TableRule orderTableRule = new TableRule("t_order", Arrays.asList("t_order_0", "t_order_1"),
                  new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()),
                  new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()),
                  dataSourceRule);

如果分片規則中的所有表或大部分表的分片策略相同,可以使用預設策略來簡化配置。一下兩種配置是等價的

  //使用了預設策略配置
  TableRule orderTableRule = new TableRule("t_order", Arrays.asList("t_order_0", "t_order_1"), dataSourceRule);
  TableRule orderItemTableRule = new TableRule("t_order_item", Arrays.asList("t_order_item_0", "t_order_item_1"), dataSourceRule);
  ShardingRule shardingRule = new ShardingRule(dataSourceRule, Arrays.asList(orderTableRule, orderItemTableRule),
                Arrays.asList(new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule))),
                new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()),
                new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()));
  //未使用預設策略配置
  TableRule orderTableRule = new TableRule("t_order", Arrays.asList("t_order_0", "t_order_1"), dataSourceRule,
          new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()),
          new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()));
  TableRule orderItemTableRule = new TableRule("t_order_item", Arrays.asList("t_order_item_0", "t_order_item_1"), dataSourceRule,
          new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()),
          new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()));
  ShardingRule shardingRule = new ShardingRule(dataSourceRule, Arrays.asList(orderTableRule, orderItemTableRule),
          Arrays.asList(new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule))));

分片鍵

分片鍵是分片策略的第一個引數。分片鍵表示的是SQL語句中WHERE中的條件列。分片鍵可以配置多個

  • 單分片策略
new TableShardingStrategy("order_id", new SingleKeyShardingAlgorithm()))
  • 多分片策略
new TableShardingStrategy(Arrays.asList("order_id""order_type", "order_date"), new MultiKeyShardingAlgorithm()))

分片演算法

分片演算法介面類圖關係如下:

演算法

繫結表

繫結表代表一組表,這組表的邏輯表與實際表之間的對映關係是相同的。比如t_ordert_order_item就是這樣一組繫結表關係,它們的分庫與分表策略是完全相同的,那麼可以使用它們的表規則將它們配置成繫結表

new BindingTableRule(Arrays.asList(orderTableRule, orderItemTableRule))

那麼在進行SQL路由時,如果SQL為

SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id=? AND o.order_id=?

其中t_order在FROM的最左側,Sharding-JDBC將會以它作為整個繫結表的主表。所有路由計算將會只使用主表的策略,那麼t_order_item表的分片計算將會使用t_order的條件。故繫結表之間的分割槽鍵要完全相同。

分片演算法詳解

單分片鍵演算法與多分片鍵演算法

這兩種演算法從名字上就可以知道前者是針對只有一個分片鍵,後者是針對有多個分片鍵的。單分片鍵演算法是多分片鍵演算法的一種簡便形式,所以完全可以使用多分片演算法去替代單分片鍵演算法。下面兩種形式是等價的

new TableShardingStrategy("order_id", new SingleKeyShardingAlgorithm()))
new TableShardingStrategy(Arrays.asList("order_id"), new MultiKeyShardingAlgorithm()))

同時在演算法內部,doSharding等方法的shardingValue入參根據使用演算法型別不同而不同 單分片鍵演算法,方法簽名

public String doEqualSharding(final Collection<String> dataSourceNames, final ShardingValue<Integer> shardingValue) 

多分片鍵演算法,方法簽名

public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue<?>> shardingValues)

分片鍵演算法型別

根據資料來源策略與表策略、單分片與多分片,這兩種組合,一共產生了4種可供實現的分片演算法的介面

  • 單分片鍵資料來源分片演算法SingleKeyDatabaseShardingAlgorithm
  • 單分片表分片演算法SingleKeyTableShardingAlgorithm
  • 多分片鍵資料來源分片演算法MultipleKeyDatabaseShardingAlgorithm
  • 多分片表分片演算法MultipleKeyTableShardingAlgorithm

單分片鍵演算法

單分片鍵演算法需要實現