本文是《ShardingSphere5.x分庫分表原理與實戰》系列的第五篇文章,我們一起梳理下ShardingSphere框架中的核心部分分片策略和分片算法,其內部針為我們提供了多種分片策略和分片算法,來應對不同的業務場景,本著拿來即用的原則。
這次將詳細介紹如何在ShardingSphere-jdbc中實戰 5 種分片策略和 12 種分片算法,自定義分片算法,比較它們的應用場景以及優劣。
圖片
全部demo案例 GitHub 地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-algorithms
分片策略是分片鍵和分片算法的組合策略,真正用于實現數據分片操作的是分片鍵與相應的分片算法。在分片策略中,分片鍵確定了數據的拆分依據,分片算法則決定了如何對分片鍵值運算,將數據路由到哪個物理分片中。
由于分片算法的獨立性,使得分片策略具有更大的靈活性和可擴展性。這意味著可以根據具體需求選擇不同的分片算法,或者開發自定義的分片算法,以適應各種不同的分片場景。在分表和分庫時使用分片策略和分片算法的方式是一致的。
注意:如果在某種分片策略中使用了不受支持的SQL操作符,比如 MYSQL 某些函數等,那么系統將無視分片策略,進行全庫表路由操作。這個在使用時要慎重!
ShardingSphere對外提供了standard、complex、hint、inline、none5種分片策略。不同的分片策略可以搭配使用不同的分片算法,這樣可以靈活的應對復雜業務場景。
標準分片策略(standard)適用于具有單一分片鍵的標準分片場景。該策略支持精確分片,即在SQL中包含=、in操作符,以及范圍分片,包括BETWEEN AND、>、<、>=、<=等范圍操作符。
該策略下有兩個屬性,分片字段shardingColumn和分片算法名shardingAlgorithmName。
spring: shardingsphere: rules: sharding: tables: t_order: # 邏輯表名稱 # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${1..10} # 分庫策略 databaseStrategy: # 分庫策略 standard: # 用于單分片鍵的標準分片場景 shardingColumn: order_id # 分片列名稱 shardingAlgorithmName: # 分片算法名稱 tableStrategy: # 分表策略,同分庫策略
行表達式分片策略(inline)適用于具有單一分片鍵的簡單分片場景,支持SQL語句中=和in操作符。
它的配置相當簡潔,該分片策略支持在配置屬性algorithm-expression中書寫Groovy表達式,用來定義對分片健的運算邏輯,無需單獨定義分片算法了。
spring: shardingsphere: rules: sharding: tables: t_order: # 邏輯表名稱 # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${1..10} # 分庫策略 databaseStrategy: # 分庫策略 inline: # 行表達式類型分片策略 algorithm-expression: db$->{order_id % 2} Groovy表達式 tableStrategy: # 分表策略,同分庫策略
復合分片策略(complex)適用于多個分片鍵的復雜分片場景,屬性shardingColumns中多個分片健以逗號分隔。支持 SQL 語句中有>、>=、<=、<、=、IN 和 BETWEEN AND 等操作符。
比如:我們希望通過user_id和order_id等多個字段共同運算得出數據路由到具體哪個分片中,就可以應用該策略。
spring: shardingsphere: rules: sharding: tables: t_order: # 邏輯表名稱 # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${1..10} # 分庫策略 databaseStrategy: # 分庫策略 complex: # 用于多分片鍵的復合分片場景 shardingColumns: order_id,user_id # 分片列名稱,多個列以逗號分隔 shardingAlgorithmName: # 分片算法名稱 tableStrategy: # 分表策略,同分庫策略
Hint強制分片策略相比于其他幾種分片策略稍有不同,該策略無需配置分片健,由外部指定分庫和分表的信息,可以讓SQL在指定的分庫、分表中執行。
使用場景:
比如,我們希望用user_id做分片健進行路由訂單數據,但是t_order表中也沒user_id這個字段啊,這時可以通過Hint API手動指定分片庫、表等信息,強制讓數據插入指定的位置。
spring: shardingsphere: rules: sharding: tables: t_order: # 邏輯表名稱 # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${1..10} # 分庫策略 databaseStrategy: # 分庫策略 hint: # Hint 分片策略 shardingAlgorithmName: # 分片算法名稱 tableStrategy: # 分表策略,同分庫策略
不分片策略比較好理解,設置了不分片策略,那么對邏輯表的所有操作將會執行全庫表路由。
spring: shardingsphere: rules: sharding: tables: t_order: # 邏輯表名稱 # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${1..10} # 分庫策略 databaseStrategy: # 分庫策略 none: # 不分片 tableStrategy: # 分表策略,同分庫策略
ShardingSphere 內置了多種分片算法,按照類型可以劃分為自動分片算法、標準分片算法、復合分片算法和 Hint 分片算法,能夠滿足我們絕大多數業務場景的需求。
此外,考慮到業務場景的復雜性,內置算法也提供了自定義分片算法的方式,我們可以通過編寫 Java代碼來完成復雜的分片邏輯。下邊逐個算法實踐一下,看看每種算法的實際執行效果。
開始前,我要吐槽下官方文檔,對于算法這種至關重要的內容,解釋描述的過于潦草,對于新手入門不友好,學習成本偏高啊
給邏輯表配置完算法后,先執行創建表的SQL,這樣就可以依據你的算法在db內快速生成分片表,所以不要總是問我要表結構了,哈哈哈。如果有不明白的小伙伴可以看我上一篇對于autoTable的介紹 分庫分表如何管理不同實例中幾萬張分片表?。
取模分片算法是內置的一種比較簡單的算法,定義算法時類型MOD,表達式大致(分片健/數據庫實例) % sharding-count,它只有一個 props 屬性sharding-count代表分片表的數量。
圖片
這個 sharding-count 數量使用時有點小坑,比如db0和db1都有分片表t_order_1,那么實際上數量只能算一個。YML核心配置如下:
spring: shardingsphere: rules: sharding: # 自動分片表規則配置 auto-tables: t_order: actual-data-sources: db$->{0..1} sharding-strategy: standard: sharding-column: order_date sharding-algorithm-name: t_order_table_mod # 分片算法定義 sharding-algorithms: t_order_table_mod: type: MOD # 取模分片算法 props: # 指定分片數量 sharding-count: 6 tables: t_order: # 邏輯表名稱 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: .... # 分表策略 table-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_table_mod
哈希取模分片算法是內置取模分片算法的一個升級版本,定義算法時類型HASH_MOD,也只有一個props屬性sharding-count代表分片的數量。表達式hash(分片健/數據庫實例) % sharding-count。
圖片
YML核心配置如下:
spring: shardingsphere: rules: sharding: # 自動分片表規則配置 auto-tables: t_order: actual-data-sources: db$->{0..1} sharding-strategy: standard: sharding-column: order_date sharding-algorithm-name: t_order_table_hash_mod # 分片算法定義 sharding-algorithms: t_order_table_hash_mod: type: HASH_MOD # 哈希取模分片算法 props: # 指定分片數量 sharding-count: 6 tables: t_order: # 邏輯表名稱 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: .... # 分表策略 table-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_table_hash_mod
基于分片容量的范圍分片算法,依據數據容量來均勻分布到分片表中。
它適用于數據增長趨勢相對均勻,按分片容量將數據均勻地分布到不同的分片表中,可以有效避免數據傾斜問題;由于數據已經被按照范圍進行分片,支持頻繁進行范圍查詢場景。
不僅如此,該算法支持動態的分片調整,可以根據實際業務數據的變化動態調整分片容量和范圍,使得系統具備更好的擴展性和靈活性。
VOLUME_RANGE算法主要有三個屬性:
圖片
看完是不是一臉懵逼,上界下界都是什么含義,我們實際使用一下就清晰了。為t_order邏輯表設置VOLUME_RANGE分片算法,range-lower下界數為 2,range-upper上界數為 20,分量容量sharding-volume 10。
yml核心配置如下:
# 分片算法定義spring: shardingsphere: rules: sharding: # 自動分片表規則配置 auto-tables: t_order: actual-data-sources: db$->{0..1} sharding-strategy: standard: sharding-column: order_date sharding-algorithm-name: t_order_table_volume_range sharding-algorithms: t_order_table_volume_range: type: VOLUME_RANGE props: range-lower: 2 # 范圍下界,超過邊界的數據會報錯 range-upper: 20 # 范圍上界,超過邊界的數據會報錯 sharding-volume: 10 # 分片容量 tables: t_order: # 邏輯表名稱 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: .... # 分表策略 table-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_table_volume_range
這個配置的意思就是說,分片健t_order_id的值在界值 [range-lower,range-upper) 范圍內,每個分片表最大存儲 10 條數據;低于下界的值 [ 1,2 ) 數據分布到 t_order_0,在界值范圍內的數據 [ 2,20 ) 遵循每滿足 10 條依次放入 t_order_1、t_order_2;超出上界的數據[ 20,∞ ) 即便前邊的分片表里未滿 10條剩下的也全部放在 t_order_3。
那么它的數據分布應該如下:
基于分片容量的范圍分片算法
接著準備插入40條數據,其中分片健字段t_order_id值從1~40,我們看到實際插入庫的數據和上邊配置的規則是一致的。超出range-lower、range-upper邊界的部分數據,比如:t_order_2表未滿 10條也不再插入,全部放入了t_order_3分片表中。
圖片
基于分片邊界的范圍分片算法,和分片容量算法不同,這個算法根據數據的取值范圍進行分片,特別適合按數值范圍頻繁查詢的場景。該算法只有一個屬性sharding-ranges為分片健值的范圍區間。
圖片
比如,我們配置sharding-ranges=10,20,30,40,它的范圍默認是從 0開始,范圍區間前閉后開。配置算法以后執行建表語句,生成數據節點分布如:
db0- |_t_order_0 |_t_order_2 |_t_order_4db1- |_t_order_1 |_t_order_3
那么它的數據分布應該如下:
[ 0,10 )數據分布到t_order_0,
[ 10,20 )數據分布到t_order_1,
[ 20,30 )數據分布到t_order_2,
[ 30,40 )數據分布到t_order_3,
[ 40,∞ )數據分布到t_order_4。
基于分片邊界的范圍分片算法
BOUNDARY_RANGE算法的YML核心配置如下:
spring: shardingsphere: rules: sharding: # 自動分片表規則配置 auto-tables: t_order: actual-data-sources: db$->{0..1} sharding-strategy: standard: sharding-column: order_date sharding-algorithm-name: t_order_table_boundary_range sharding-algorithms: # 基于分片邊界的范圍分片算法 t_order_table_boundary_range: type: BOUNDARY_RANGE props: sharding-ranges: 10,20,30,40 # 分片的范圍邊界,多個范圍邊界以逗號分隔 tables: t_order: # 邏輯表名稱 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: .... # 分表策略 table-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_table_boundary_range
也插入40條數據,其中分片健字段t_order_id值從1~40,和上邊分析的數據分布結果大致相同。看到第一張分片表中 t_order_0 只有 9 條數據,這是因為咱們插入數據的分片健值是從 1 開始,但算法是從 0 開始計算。
圖片
自動時間段分片算法,適用于以時間字段作為分片健的分片場景,和VOLUME_RANGE基于容量的分片算法用法有點類似,不同的是AUTO_INTERVAL依據時間段進行分片。主要有三個屬性datetime-lower分片健值開始時間(下界)、datetime-upper分片健值結束時間(上界)、sharding-seconds單一分片表所能容納的時間段。
圖片
這里分片健已經從t_order_id替換成了order_date。現在屬性 datetime-lower 設為 2023-01-01 00:00:00,datetime-upper 設為 2025-01-01 00:00:00,sharding-seconds為 31536000 秒(一年)。策略配置上有些改動,將分庫和分表的算法全替換成AUTO_INTERVAL。
YML核心配置如下:
spring: shardingsphere: rules: sharding: # 自動分片表規則配置 auto-tables: t_order: actual-data-sources: db$->{0..1} sharding-strategy: standard: sharding-column: order_date sharding-algorithm-name: t_order_table_auto_interval # 分片算法定義 sharding-algorithms: # 自動時間段分片算法 t_order_table_auto_interval: type: AUTO_INTERVAL props: datetime-lower: '2023-01-01 00:00:00' # 分片的起始時間范圍,時間戳格式:yyyy-MM-dd HH:mm:ss datetime-upper: '2025-01-01 00:00:00' # 分片的結束時間范圍,時間戳格式:yyyy-MM-dd HH:mm:ss sharding-seconds: 31536000 # 單一分片所能承載的最大時間,單位:秒,允許分片鍵的時間戳格式的秒帶有時間精度,但秒后的時間精度會被自動抹去 tables: # 邏輯表名稱 t_order: # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: standard: sharding-column: order_date sharding-algorithm-name: t_order_table_auto_interval # 分表策略# table-strategy:# standard:# sharding-column: order_date# sharding-algorithm-name: t_order_table_auto_interval
只要你理解了上邊 VOLUME_RANGE 算法的數據分布規則,那么這個算法也很容易明白,分片健值在界值范圍內 [datetime-lower,datetime-upper) 遵循每滿足 sharding-seconds 時間段的數據放入對應分片表,超出界值的數據上下順延到其他分片中。
它的數據分布應該如下:
為了方便測試,手動執行插入不同日期的數據,按照上邊配置的規則應該t_order_0會有一條 23 年的數據,t_order_1 中有兩條 24 年的數據,t_order_2 中有兩條 25 年的數據,t_order_3 中有兩條 26、27 年的數據。
// 放入 t_order_0 分片表INSERT INTO `t_order` VALUES (1, '2023-03-20 00:00:00', 1, '1', 1, 1.00);// 放入 t_order_1 分片表INSERT INTO `t_order` VALUES (2, '2024-03-20 00:00:00', 2, '2', 2,1.00);INSERT INTO `t_order` VALUES (3, '2024-03-20 00:00:00', 3, '3', 3, 1.00);// 放入 t_order_2 分片表INSERT INTO `t_order` VALUES (4,'2025-03-20 00:00:00',4, '4', 4, 1.00);INSERT INTO `t_order` VALUES (5,'2025-03-20 00:00:00',5, '5', 5, 1.00);// 放入 t_order_3 分片表INSERT INTO `t_order` VALUES (6,'2026-03-20 00:00:00',6, '6', 6, 1.00);INSERT INTO `t_order` VALUES (7,'2027-03-20 11:19:58',7, '7', 7, 1.00);
查看實際的數據分布情況和預想的結果完全一致,至此內置算法全部使用大成。
行表達式分片算法,適用于比較簡單的分片場景,利用Groovy表達式在算法屬性內,直接書寫分片邏輯,省卻了配置和代碼開發,只支持SQL語句中的 = 和 IN 的分片操作,只支持單分片鍵。
圖片
該算法有兩屬性:
YML核心配置如下:
spring: shardingsphere: # 具體規則配置 rules: sharding: # 分片算法定義 sharding-algorithms: # 標準分片算法 # 行表達式分片算法 t_order_table_inline: type: INLINE props: algorithm-expression: t_order_$->{order_id % 3} # 分片算法的行表達式 allow-range-query-with-inline-sharding: false # 是否允許范圍查詢。注意:范圍查詢會無視分片策略,進行全路由,默認 false tables: # 邏輯表名稱 t_order: # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_database_algorithms # 分表策略 table-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_table_inline
時間范圍分片算法,針對于時間字段(字符串類型)作為分片健的范圍分片算法,適用于按照天、月、年這種固定區間的數據分片。 上邊使用其它時間分片算法時,用的都是t_order_n后綴編號格式的分片表。但業務上往往需要的可能是按月、年t_order_yyyyMM的這種分片表格式。
時間范圍分片算法(INTERVAL),可以輕松實現這種場景,它的屬性比較多,逐個解釋下:
圖片
接下來實現個按月存儲數據的場景,用t_order_202401~t_order_202406 6張分片表存儲前半年的數據,每張分片表存儲一個月的數據。interval_value字段作為分片健,時間字符串類型,允許的分片值時間范圍 2024-01-01 00:00:00~2024-06-30 23:59:59 不在范圍內插入報錯。
spring: shardingsphere: rules: sharding: # 分片算法定義 sharding-algorithms: t_order_database_mod: type: MOD props: sharding-count: 2 # 指定分片數量 t_order_table_interval: type: INTERVAL props: datetime-pattern: "yyyy-MM-dd HH:mm:ss" # 分片字段格式 datetime-lower: "2024-01-01 00:00:00" # 范圍下限 datetime-upper: "2024-06-30 23:59:59" # 范圍上限 sharding-suffix-pattern: "yyyyMM" # 分片名后綴,可以是MM,yyyyMMdd等。 datetime-interval-amount: 1 # 分片間隔,這里指一個月 datetime-interval-unit: "MONTHS" # 分片間隔單位 tables: # 邏輯表名稱 t_order: # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${202401..202406} # 分庫策略 database-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_database_mod # 分表策略 table-strategy: standard: sharding-column: interval_value sharding-algorithm-name: t_order_table_interval keyGenerateStrategy: column: id keyGeneratorName: t_order_snowflake
配置完成后插入測試數據 1月~7月,正常情況下前 6 個月的數據會正常插入,超過界值的 7月數據應該會報錯。
// 放入 t_order_202401 分片表INSERT INTO `t_order` VALUES (1, 1, '1', 1, 1.00, '2024-01-01 00:00:00', 1);// 放入 t_order_202402 分片表INSERT INTO `t_order` VALUES (2, 2, '2', 2, 1.00, '2024-02-01 00:00:00', 1);// 放入 t_order_202403 分片表INSERT INTO `t_order` VALUES (3, 3, '3', 3, 1.00, '2024-03-01 00:00:00', 1);// 放入 t_order_202404 分片表INSERT INTO `t_order` VALUES (4, 4, '4', 4, 1.00, '2024-04-01 00:00:00', 1);// 放入 t_order_202405 分片表INSERT INTO `t_order` VALUES (5, 5, '5', 5, 1.00, '2024-05-01 00:00:00', 1);// 放入 t_order_202406 分片表INSERT INTO `t_order` VALUES (6, 6, '6', 6, 1.00, '2024-06-01 00:00:00', 1);// 插入會報錯INSERT INTO `t_order` VALUES (7, 7, '7', 7, 1.00, '2024-07-01 00:00:00', 1);
看到實際的入庫的效果和預期的一致,一月的數據存到t_order_202401,二月的數據存到t_order_202402~,在插入 7月數據的時候報錯了。
圖片
ShardingSphere 提供了三種基于散列散列算法的CosId(它是一款性能極高分布式ID生成器)分片算法,這個算法的核心思想是通過散列算法對CosId生成的分布式ID和分片鍵值進行處理,以確定數據應該存放在哪個具體的數據節點上。
使用散列算法的優勢,可以將數據按照一定規則映射到不同的數據節點上,能夠確保數據的均勻分布,避免某些節點負載過重或者數據傾斜的情況。
三個算法與其他分片算法主要區別在于底層的實現,在配置上使用上基本沒太多區別。
基于 CosId 的取模分片算法和普通的MOD算法使用上略有不同,mod為分片數量,logic-name-prefix分片數據源或真實表的前綴格式。
圖片
yml核心配置如下:
spring: shardingsphere: rules: sharding: # 分片算法定義 sharding-algorithms: t_order_database_mod: type: MOD props: sharding-count: 2 # 指定分片數量 # 8、基于 CosId 的取模分片算法 t_order_table_cosid_mod: type: COSID_MOD props: mod: 3 # 分片數量 logic-name-prefix: t_order_ # 分片數據源或真實表的前綴格式 tables: # 邏輯表名稱 t_order: # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_database_mod # 分表策略 table-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_table_cosid_mod keyGenerateStrategy: column: id keyGeneratorName: t_order_snowflake
基于 CosId 的固定時間范圍的分片算法,和INTERVAL算法的用法很相似,不同點在于增加了zone-id時區屬性,logic-name-prefix分片數據源或真實表的前綴格式,上下界datetime-lower、datetime-upper范圍的時間格式是固定的yyyy-MM-dd HH:mm:ss。
圖片
yml核心配置如下:
spring: shardingsphere: rules: sharding: # 分片算法定義 sharding-algorithms: t_order_database_mod: type: MOD props: sharding-count: 2 # 指定分片數量 # 基于 CosId 的固定時間范圍的分片算法 t_order_table_cosid_interval: type: COSID_INTERVAL props: zone-id: "Asia/Shanghai" # 時區,必須遵循 java.time.ZoneId 的所含值。 例如:Asia/Shanghai logic-name-prefix: t_order_ # 分片數據源或真實表的前綴格式 sharding-suffix-pattern: "yyyyMM" # 分片數據源或真實表的后綴格式,必須遵循 Java DateTimeFormatter 的格式,必須和 datetime-interval-unit 保持一致。例如:yyyyMM datetime-lower: "2024-01-01 00:00:00" # 時間分片下界值,格式與 yyyy-MM-dd HH:mm:ss 的時間戳格式一致 datetime-upper: "2024-12-31 00:00:00" # 時間分片上界值,格式與 yyyy-MM-dd HH:mm:ss 的時間戳格式一致 datetime-interval-unit: "MONTHS" # 分片鍵時間間隔單位,必須遵循 Java ChronoUnit 的枚舉值。例如:MONTHS datetime-interval-amount: 1 # 分片鍵時間間隔,超過該時間間隔將進入下一分片 tables: # 邏輯表名稱 t_order: # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${202401..202412} # 分庫策略 database-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_database_mod # 分表策略 table-strategy: standard: sharding-column: interval_value sharding-algorithm-name: t_order_table_cosid_interval keyGenerateStrategy: column: id keyGeneratorName: t_order_snowflake
基于 CosId 的雪花ID固定時間范圍的分片算法,和上邊的COSID_INTERVAL算法不同之處在于,底層用于散列的COSID的生成方式是基于雪花算法(Snowflake),內部結合了時間戳、節點標識符和序列號等,這樣有助于數據分布更均勻些。
圖片
使用除了type類型不同COSID_INTERVAL_SNOWFLAKE外,其他屬性用法和COSID_INTERVAL完全一致。yml核心配置如下:
spring: shardingsphere: rules: sharding: # 分片算法定義 sharding-algorithms: t_order_database_mod: type: MOD props: sharding-count: 2 # 指定分片數量 # 基于 CosId 的固定時間范圍的分片算法 t_order_table_cosid_interval_snowflake: type: COSID_INTERVAL_SNOWFLAKE props: zone-id: "Asia/Shanghai" # 時區,必須遵循 java.time.ZoneId 的所含值。 例如:Asia/Shanghai logic-name-prefix: t_order_ # 分片數據源或真實表的前綴格式 sharding-suffix-pattern: "yyyyMM" # 分片數據源或真實表的后綴格式,必須遵循 Java DateTimeFormatter 的格式,必須和 datetime-interval-unit 保持一致。例如:yyyyMM datetime-lower: "2024-01-01 00:00:00" # 時間分片下界值,格式與 yyyy-MM-dd HH:mm:ss 的時間戳格式一致 datetime-upper: "2024-12-31 00:00:00" # 時間分片上界值,格式與 yyyy-MM-dd HH:mm:ss 的時間戳格式一致 datetime-interval-unit: "MONTHS" # 分片鍵時間間隔單位,必須遵循 Java ChronoUnit 的枚舉值。例如:MONTHS datetime-interval-amount: 1 # 分片鍵時間間隔,超過該時間間隔將進入下一分片 tables: # 邏輯表名稱 t_order: # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${202401..202412} # 分庫策略 database-strategy: standard: sharding-column: order_id sharding-algorithm-name: t_order_database_mod # 分表策略 table-strategy: standard: sharding-column: interval_value sharding-algorithm-name: t_order_table_cosid_interval_snowflake keyGenerateStrategy: column: id keyGeneratorName: t_order_snowflake
復合行表達式分片算法,適用于多分片健的簡單分片場景,和行表達式分片算法使用的方式基本一樣。多了一個屬性sharding-columns分片列名稱,多個列用逗號分隔。特別注意:使用多分片鍵復合算法,一定要基于復合分片策略進行設置。
圖片
我們對現有的分庫分表算法進行了改進,將分片策略修改為complex,sharding-columns單個分片鍵升級為多個分片鍵逗號分隔。例如,將分庫表達式從db$->{order_id % 2}調整為db$->{(order_id + user_id) % 2},就實現了多個分片鍵的應用。
yml核心的配置如下:
spring: shardingsphere: # 具體規則配置 rules: sharding: # 分片算法定義 sharding-algorithms: t_order_database_complex_inline_algorithms: type: COMPLEX_INLINE props: sharding-columns: order_id, user_id # 分片列名稱,多個列用逗號分隔。 algorithm-expression: db$->{(order_id + user_id) % 2} # 分片算法的行表達式 allow-range-query-with-inline-sharding: false # 是否允許范圍查詢。注意:范圍查詢會無視分片策略,進行全路由,默認 false # 11、復合行表達式分片算法 t_order_table_complex_inline: type: COMPLEX_INLINE props: sharding-columns: order_id, user_id # 分片列名稱,多個列用逗號分隔。 algorithm-expression: t_order_$->{ (order_id + user_id) % 3 } # 分片算法的行表達式 allow-range-query-with-inline-sharding: false # 是否允許范圍查詢。注意:范圍查詢會無視分片策略,進行全路由,默認 false tables: # 邏輯表名稱 t_order: # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: complex: shardingColumns: order_id, user_id sharding-algorithm-name: t_order_database_complex_inline_algorithms # 分表策略 table-strategy: complex: shardingColumns: order_id, user_id sharding-algorithm-name: t_order_table_complex_inline keyGenerateStrategy: column: id keyGeneratorName: t_order_snowflake
Hint 行表達式分片算法(強制路由分片算法),允許我們指定數據分布的分片庫和分表的位置。這個算法只有一個屬性algorithm-expression,直接利用Groovy表達式在其中書寫分片邏輯。
如果想要向db0.t_order_1分片表中插入一條數據,但我的 Insert SQL 中并沒有分片健呀,執意執行插入操作可能就會導致全庫表路由,插入的數據就會重復,顯然是不能接受的。Hint 算法可以很好的解決此場景。
HINT_INLINE 算法一定要在 HINT 分片策略內使用,否則會報錯。
核心的配置如下:其中兩個表達式db$->{Integer.valueOf(value) % 2}和t_order_$->{Integer.valueOf(value) % 3}中的value值分別是我們通過 Hint API 傳入的分庫值和分表值。
spring: shardingsphere: rules: sharding: # 分片算法定義 sharding-algorithms: # Hint 行表達式分片算法 t_order_database_hint_inline: type: HINT_INLINE props: algorithm-expression: db$->{Integer.valueOf(value) % 2} # 分片算法的行表達式,默認值${value} t_order_table_hint_inline: type: HINT_INLINE props: algorithm-expression: t_order_$->{Integer.valueOf(value) % 3} # 分片算法的行表達式,默認值${value} tables: # 邏輯表名稱 t_order: # 數據節點:數據庫.分片表 actual-data-nodes: db$->{0..1}.t_order_${0..2} # 分庫策略 database-strategy: hint: sharding-algorithm-name: t_order_database_hint_inline # 分表策略 table-strategy: hint: sharding-algorithm-name: t_order_table_hint_inline keyGenerateStrategy: column: id keyGeneratorName: t_order_snowflake
配置完分片算法,如何將value值傳遞進來?通過HintManager設置邏輯表的分庫addDatabaseShardingValue、分表addTableShardingValue,強制數據分布到指定位置。
@DisplayName("測試 hint_inline 分片算法插入數據")@Testpublic void insertHintInlineTableTest() { HintManager hintManager = HintManager.getInstance(); hintManager.clearShardingValues(); // 設置邏輯表 t_order 的分庫值 hintManager.addDatabaseShardingValue("t_order", 0); // 設置邏輯表 t_order 的分表值 hintManager.addTableShardingValue("t_order", 1); // 1%3 = 1 所以放入 db0.t_order_1 分片表 jdbcTemplate.execute("INSERT INTO `t_order`(`id`,`order_date`,`order_id`, `order_number`, `customer_id`, `total_amount`, `interval_value`, `user_id`) VALUES (1, '2024-03-20 00:00:00', 1, '1', 1, 1.00, '2024-01-01 00:00:00', 1);"); hintManager.close();}
ShardingSphere 通過使用ThreadLocal管理強制路由配置,可以通過編程的方式向HintManager中添加分片值,該分片值僅在當前線程內生效。
按我們設定的數據節點位置,插入一條測試數據,看到確實存在了db0.t_order_1中,完美!
圖片
本文中我們講解了ShardingSphere-jdbc所支持的12種分片算法,每種算法都具有獨特的特點。在實際應用中,需要結合具體的業務場景來靈活選擇和應用適合的分片算法。
由于篇幅已經夠長了,剩下的 3 種自定義分片算法會在下一篇中詳細介紹。
全部demo案例 GitHub 地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-algorithms
本文鏈接:http://www.www897cc.com/showinfo-26-79456-0.html一口氣搞懂分庫分表 12 種分片算法,大廠都在用
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com