ShardingSphere數據分片

  • 2022 年 7 月 25 日
  • 筆記

碼農在囧途

堅持是一件比較難的事,堅持並不是自欺欺人的一種自我麻痹和安慰,也不是做給被人的,我覺得,堅持的本質並沒有帶着過多的功利主義,如果滿是功利主義,那麼這個堅持並不會長久,也不會有好的收穫,堅持應該帶着熱愛,帶着思想,把它當成習慣,但是並不是內卷,而是一種發自內心的喜歡和平實!希望我們都有自己的堅持,堅持寫一篇文章,堅持愛一個人,堅持讀一本書,堅持走向遠方!

image

前言

上一篇我們說了ShardingSphere的讀寫分離,使用讀寫分離能夠減輕單庫的讀寫操作,從而提升數據庫的吞吐量,但是當數據庫中表的數據量到達一定數量時,我們可能就會需要進行分片了,
分片又分為垂直分片和水平分片,下面我們對二者進行簡單的分析。

垂直分片

我們的一個數據庫中通常是有很多數據表的,不過可能由於我們的分類不到位,就會出現澇的澇死旱的旱死的局面,比如某些數據表的讀寫操作十分頻繁,而我的這個庫中大量的集中了這種
讀寫操作頻繁的表,那麼整體的吞吐量就會降低,而某個庫中又集中了讀寫不頻繁的表,吞吐量十分的高(但是好像沒什麼卵用),所以我們應該合理的分配,以保證整理的吞吐量達到最大值,
下圖將數據表各分到了一個數據庫中。

不過垂直分片不能從根本上解決讀寫瓶頸,因為不管你再怎麼分,所有的數據始終都集中在一張表裏面,就算數據庫的性能再好,也解決不了這個問題。所以我們需要進行
更加細粒度的劃分,下面我們來講解水平分片。

水平分片

水平分片又可以叫做橫向拆分,就是將一張大表拆分為若干張小表,比如我一張表中有1億條數據,那麼我拆分為10張表,每張表中存1000萬條數據,那麼效率就會變高,
還有些數據需要進行分類和歸檔,那麼我們也需要進行分表,之前我們系統中一個表用來存儲文檔信息,有十多年因為數據量十分龐大,在業務中需要對文檔進行排序等操作,本來查詢就比較
耗時了,再加上需要進行邏輯上的處理,所以就更加耗時,於是就進行了分表,將每一年的數據存進一個表,這樣就提高了查詢效率,並且更加容易對數據進行追蹤和管理,如下就是水平
分片的圖例。

ShardingSphere數據分片實戰

使用ShardingSphere數據分片,我們只需通過簡單的配置就能實現,ShardingSphere幫我們屏蔽了底層邏輯,我們也可通過ShardingSphere預留的
接口和SPI進行擴展我們的需求,比如可以實現我們自己的分片算法,主鍵生成策略等等。

下面演示將文檔按照年份進行分表,將文檔數據分表至2013年至2022年來存,一般我們的配置文件都是配置在nacos上面,所以能夠靈活的進行配置,
當到了2023年,我們可以添加一個2023年的表,改下nacos的配置,當然,一般會先預留出數據表,nacos上面也留出空間,我們的是預留到2032年,
留出了10年。

yml文件

我們重點關注下面的一些配置,actual-data-nodes代表進行分片的表,使用表達式,document.document_$->{2013..2022}代表document數據庫
下面的document_前綴的表進行分片,如document_2022document_2021{2013..2022}代表2013到2022這個區間,sharding-column是分片列,
是我們數據表中的某個字段,就是根據它來進行分片,sharding-algorithms是分片算法,我們可以通過SPI來實現自己的分片算法,接口是StandardShardingAlgorithm
如下我們使用的是INLINE基於行表達式的分片算法,algorithm-expression是分片表達式,ShardingSphere底層會進行解析表達式,然後分片到對應的數據表上面,
我們的表達式是document_$->{year},也就是根據年進行分片,當然,我們可以根據自己的需求去寫表達式,比如根據主鍵取模進行分片等,需要根據我們的實際場景去做,
key-generate-strategy是主鍵生成策略,ShardingSphere支持自定義主鍵生成策略,我們只需要通過SPI就可以實現,接口是KeyGenerateAlgorithm,已經
實現了UUIDsnowflake雪花算法等主鍵生成策略。

spring:
  shardingsphere:
    mode:
      type: Standalone
      repository:
        type: File
      overwrite: true
    datasource:
      names: document
      document:
        jdbc-url: jdbc:mysql://localhost:3306/document?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.jdbc.Driver
        username: root
        password: qwer123@
    rules:
      sharding:
        tables:
          document:
            actual-data-nodes: document.document_$->{2013..2022}
            table-strategy:
              standard:
                sharding-column: year #分片列
                sharding-algorithm-name: document-inline # 分片算法名稱
            key-generate-strategy:
              column: id # 主鍵列
              key-generator-name: timestamp #主鍵生成算法
        sharding-algorithms: #分片算法
          document-inline:
            type: INLINE
            props:
              algorithm-expression: document_$->{year}
        key-generators:
          timestamp:
            type: SNOWFLAKE

測試數據數據分片

虛幻插入十次,每次都插入2013年到2022年的數據。

void addDocSliceYear(){
    for (int i = 0; i < 10; i++) {
        for (int year = 2013; year <= 2022; year++) {
            Document document = new Document()
                .setDocumentName("document year【" + year + "】")
                .setDocumentDetail("year【" + year + "】")
                .setYear(year);
            documentService.save(document);
        }
    }
}

我們可以看出,數據分片成功,我們看一下分片的數據怎麼查詢的(此處只是單表查詢),我們看一下ShardingSphere-SQL輸出的sql語句

SELECT  id,document_name,document_detail,year  FROM document_2013 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2014 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2015 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2016 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2017 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2018 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2019 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2020 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2021 
UNION ALL SELECT  id,document_name,document_detail,year  FROM document_2022

從控制台打印的SQL語句中看出,ShardingSphere分片查詢使用的是UNION ALL,UNION ALL實現把前後兩個SELECT集合的數據聯合起來,組成一個結果集查詢輸出,
聯合查詢需要每個表中的的字段相同,字段類型相同,數量相同,這也是分片的基本要求。

上面我們只演示了單表的數據分片查詢,如果是多表查詢,我們需要配置binding-tables綁定表,這樣能夠減少查詢的笛卡爾積,從而提升查詢效率,我們就不做
詳細的介紹,可去官網自己查看。

分片算法

ShardingSphere的分片算法有多種,我們也可以自己實現一套分片算法,通過SPI,分片算法的頂層接口是ShardingAlgorithm,目前實現了多種算法。

BoundaryBasedRangeShardingAlgorithm: 基於分片邊界的範圍分片算法

VolumeBasedRangeShardingAlgorithm: 基於分片容量的範圍分片算法

ComplexInlineShardingAlgorithm: 基於行表達式的複合分片算法

AutoIntervalShardingAlgorithm: 基於可變時間範圍的分片算法

ClassBasedShardingAlgorithm: 基於自定義類的分片算法

HintInlineShardingAlgorithm: 基於行表達式的 Hint 分片算法

IntervalShardingAlgorithm: 基於固定時間範圍的分片算法

HashModShardingAlgorithm: 基於哈希取模的分片算法

InlineShardingAlgorithm: 基於行表達式的分片算法

ModShardingAlgorithm: 基於取模的分片算法

CosIdModShardingAlgorithm: 基於 CosId 的取模分片算法

CosIdIntervalShardingAlgorithm: 基於 CosId 的固定時間範圍的分片算法

CosIdSnowflakeIntervalShardingAlgorithm: 基於 CosId 的雪花ID固定時間範圍的分片算法

分佈式主鍵生成算法

ShardingSphere也可以自定義實現主鍵生成策略,通過SPI,頂層接口為KeyGenerateAlgorithm,目前實現的算法有。

SnowflakeKeyGenerateAlgorithm 基於雪花算法的分佈式主鍵生成算法

UUIDKeyGenerateAlgorithm: 基於 UUID 的分佈式主鍵生成算法

CosIdKeyGenerateAlgorithm: 基於 CosId 的分佈式主鍵生成算法

CosIdSnowflakeKeyGenerateAlgorithm: 基於 CosId 的雪花算法分佈式主鍵生成算法

NanoIdKeyGenerateAlgorithm: 基於 NanoId 的分佈式主鍵生成算法

總結

ShardingSphere能夠方便的實現數據分片,但是數據分片本身就是一件迫不得已的事情,它會是我們的業務變得更加的複雜,在設計的時候需要經過嚴格的考量後再進行數據分片,防止出現一些不必要的麻煩。

關於ShardingSphere的數據分片,我們就說到這裡,感謝你的觀看,我們下期再見。