數據庫中間件ShardingSphere-ShardingJdbc使用(一)數據分片

背景:

我們實際開發中,總有幾張和業務相關的大表,這裏的大表是指數據量巨大。如用戶表、訂單表,又或者公司業務中的主表,可能很快這種表的數據就達到了百萬、千萬、億級別的規模,並且增長規模一直很快。這種情況下,單表已經滿足不了了存儲需求了,同時,這麼大的數據量,即使搭配合理的索引,數據庫查詢也是很慢的。這時就需要對這些大表進行分庫、分表。

例如:

user表現在數據增長很快,這時對user庫、表。通過部署多個MySQL實例來進行拓展。每個MySQL實例上都會有user庫,每個user庫裏又有user_N(N爲0,1...),N張數據結構一致,只不過表名不同的user表,來存儲數據。

分庫、分表的基本原則爲:

建議每個表的數據量不超過1000萬行數據

分表的數目選擇:

N =(未來3到5年內總共的記錄行數) / 單張表建議記錄行數 (單張表建議記錄行數 = 1000萬)

N就是每個庫的分表數。建議一次分夠,如果因爲分不夠造成的擴容,是很麻煩的,特別是分表的鍵是採用hash算法分的

分庫的數目選擇:

按照存儲容量來計算 = (3到5年內的存儲容量)/ 單個庫建議存儲容量 (單個庫建議存儲容量 <300G以內)

ShardingSphere官網

使用ShardingSphere的原因是,原來很多的數據庫中間件都已不再維護,如mycat、tddl,只有ShardingSphere一直維護,並且今年成功從Apache畢業,成爲頂級項目。美團開源的Zebra的配置和ShardingSphere相比,太過複雜.

對數據庫中間件設計的文章感興趣的同學,可以看下美團這篇文章

數據庫中間件有兩種代理方案,客戶端代理(DataSource)、服務端代理(數據庫代理),以下內容引用自美團文章

  • 服務端代理(proxy:代理數據庫)中: 我們獨立部署一個代理服務,這個代理服務背後管理多個數據庫實例。而在應用中,我們通過一個普通的數據源(c3p0、druid、dbcp等)與代理服務器建立連接,所有的sql操作語句都是發送給這個代理,由這個代理去操作底層數據庫,得到結果並返回給應用。在這種方案下,分庫分表和讀寫分離的邏輯對開發人員是完全透明的。

  • 客戶端代理(datasource:代理數據源): 應用程序需要使用一個特定的數據源,其作用是代理,內部管理了多個普通的數據源(c3p0、druid、dbcp等),每個普通數據源各自與不同的庫建立連接。應用程序產生的sql交給數據源代理進行處理,數據源內部對sql進行必要的操作,如sql改寫等,然後交給各個普通的數據源去執行,將得到的結果進行合併,返回給應用。數據源代理通常也實現了JDBC規範定義的API,因此能夠直接與orm框架整合。在這種方案下,用戶的代碼需要修改,使用這個代理的數據源,而不是直接使用c3p0、druid、dbcp這樣的連接池

ShardingSphere-jdbc屬於客戶端(數據源代理)

ShardingSpehere將分庫、分表統稱爲數據分片

一、添加依賴

        <dependency>
            <groupId>org.apache.shardingsphere</groupId>
            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
            <version>4.1.0</version>
        </dependency>

二、配置

server:
  port: 8999
spring:
  application:
    name: mybatis-demo
  shardingsphere:
    datasource:
      # 數據庫的別名
      names: ds0,ds1
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/dhb?serverTimezone=UTC
        password: 12345
        username: root
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3310/dhb?serverTimezone=UTC
        password: 12345
        username: root
    sharding:
      # 默認分庫策略
      default-database-strategy:
        inline:
          sharding-column: id
          algorithm-expression: ds$->{id % 2}
      # 默認分表策略
      default-table-strategy:
        inline:
          sharding-column: age
          algorithm-expression: user_$->{age % 2}
      # 數據節點
      tables:
        user:
          actual-data-nodes: ds$->{0..1}.user_$->{0..1}
      # 默認數據庫
      default-data-source-name: ds0
    props:
      # 打印SQL
      sql.show: true
      check:
        table:
          metadata:
          # 是否在啓動時檢查分表元數據一致性
          enabled: true
    # 因爲Druid數據源和默認的數據源衝突,添加此配置
  main:
    allow-bean-definition-overriding: true

配置說明:

本地有兩個MySQL實例,分別爲3306、3310,每個數據庫下都有dhb數據庫,每個數據庫都有user_0、user_1兩張user表,如下圖:

實例截圖

配置文件說明:

配置文件中的分庫策略是將根據id %2 ,結果如果是0,則走ds0,實例3306的數據庫;結果是1,則走ds1,實例3310的數據庫。

選擇了數據庫之後,怎麼選擇入哪一張表呢?根據age % 2,如果爲0,則走user_0,如果是1,則走user_1。

關於邏輯表、真實表、數據節點概念參見官方文檔

配置文件中分片,屬於行表達式分片,實際業務中,可以自己實現官方的接口,實現自己業務需要的分庫、分表算法,具體實現的4個接口參見分片。StandardShardingStrategy、ComplexShardingStrategy、HintShardingStrategy

關於行表達式的寫法可見官方example

特別注意:

如果使用了阿里的Druid數據源,啓動的時候會報數據源衝突,則使用上述配置文件的最後一行配置即可。

三、實體類,使用、Lambok和Mybatis-plus簡化操作,這裏的table名字是邏輯表名字-user,實際對應的表有ds0.user_0、ds0.user_1、ds1.user_0、ds1.user_1四張表

@Data
@TableName(value = "user")
public class UserItem {
    @TableId
    private Long id;
    private String name;
    private Integer age;
    private Integer del;
}

四、使用。插入一條數據

控制檯打印SQL入下

運行截圖

最終shardingsphere-jdbc最終根據配置的分庫、分表策略將數據寫入ds0-3306實例庫中的user_1表中。

當查詢的時候,如果條件是根據分片鍵查詢,那麼最終定位到某一個庫的某一個表,如果條件中沒有分片鍵,則會進行全路由,也就是四個庫都查

ShardingSphere-jdbc爲我們做了,根據配置的分片策略,進行 SQL解析 => 執行器優化 => SQL路由 => SQL改寫 => SQL執行 => 結果歸併 工作。具體文檔見內核剖析

以上僅僅是一個使用小例子,實際業務場景比這更復雜,如主子表的分片、分片表和爲分片的表join查詢等等

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