SpringBoot中4種數(shù)據(jù)水平分片策略
一、前言
數(shù)據(jù)水平分片作為一種水平擴(kuò)展策略,通過將數(shù)據(jù)分散到多個(gè)物理節(jié)點(diǎn)上,有效解決了存儲(chǔ)容量和性能瓶頸問題。
而分片鍵(Sharding Key)作為數(shù)據(jù)分片的核心,決定了數(shù)據(jù)如何在各個(gè)分片中分布,直接影響到分片系統(tǒng)的性能、數(shù)據(jù)分布均衡性以及查詢效率。
本文將分享4種數(shù)據(jù)分片策略。
二、哈希分片
2.1 原理
哈希分片通過對(duì)分片鍵值應(yīng)用哈希函數(shù),然后對(duì)分片數(shù)量取模,將數(shù)據(jù)均勻分布到各個(gè)分片。
分片索引 = hash(分片鍵值) % 分片數(shù)量
2.2 SpringBoot實(shí)現(xiàn)
在SpringBoot中,我們可以使用ShardingSphere-JDBC實(shí)現(xiàn)哈希分片。首先添加依賴:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.1.2</version>
</dependency>然后在application.yml中配置哈希分片策略:
spring:
shardingsphere:
datasource:
names: ds0,ds1,ds2,ds3
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/order_db_0
username: root
password: password
# 其他數(shù)據(jù)源配置...
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds${0..3}.t_order
database-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: order-id-hash
sharding-algorithms:
order-id-hash:
type: HASH_MOD
props:
sharding-count: 4在實(shí)體類和Repository中使用:
@Entity
@Table(name = "t_order")
public class Order {
@Id
private Long orderId; // 分片鍵
private Long userId;
private BigDecimal amount;
private String status;
// getters and setters
}
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
// 查詢方法
}2.3 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 數(shù)據(jù)分布均勻:哈希函數(shù)確保數(shù)據(jù)在各分片上分布均衡
- 讀寫負(fù)載均衡:避免熱點(diǎn)分片問題
- 簡單易實(shí)現(xiàn):配置簡單,無需復(fù)雜的分片算法
缺點(diǎn):
- 不支持范圍查詢:相鄰的鍵值會(huì)被分散到不同分片,導(dǎo)致范圍查詢需要訪問所有分片
- 分片擴(kuò)縮容困難:增加或減少分片數(shù)量時(shí),需要重新哈希和遷移大量數(shù)據(jù)
- 不易直觀理解:數(shù)據(jù)分布不直觀,難以預(yù)測特定記錄在哪個(gè)分片
2.4 適用場景
讀寫操作頻繁且均衡的OLTP系統(tǒng)
點(diǎn)查詢(如通過主鍵或唯一索引查詢)為主的應(yīng)用
對(duì)數(shù)據(jù)分布均勻性要求高的系統(tǒng)
分片數(shù)量相對(duì)穩(wěn)定的環(huán)境
三、范圍分片
3.1 原理
范圍分片鍵通過將數(shù)據(jù)按照分片鍵的值范圍劃分到不同的分片中。每個(gè)分片負(fù)責(zé)存儲(chǔ)特定范圍內(nèi)的數(shù)據(jù),數(shù)據(jù)在邏輯上保持有序。
如:訂單ID 1-1000000 存儲(chǔ)在分片1
訂單ID 1000001-2000000 存儲(chǔ)在分片2
...
3.2 SpringBoot實(shí)現(xiàn)
使用ShardingSphere-JDBC實(shí)現(xiàn)范圍分片:
spring:
shardingsphere:
datasource:
names: ds0,ds1,ds2,ds3
# 數(shù)據(jù)源配置...
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds${0..3}.t_order
database-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: order-id-range
sharding-algorithms:
order-id-range:
type: RANGE
props:
strategy: standard
range-lower: 0,1000000,2000000,3000000
range-upper: 999999,1999999,2999999,3999999自定義更復(fù)雜的范圍分片算法:
@Component
public class CustomRangeShardingAlgorithm implements StandardShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
Long orderId = shardingValue.getValue();
for (String targetName : availableTargetNames) {
if (targetName.endsWith("0") && orderId <= 1000000) {
return targetName;
} else if (targetName.endsWith("1") && orderId > 1000000 && orderId <= 2000000) {
return targetName;
} else if (targetName.endsWith("2") && orderId > 2000000 && orderId <= 3000000) {
return targetName;
} else if (targetName.endsWith("3") && orderId > 3000000) {
return targetName;
}
}
throw new UnsupportedOperationException("No available target name for order id: " + orderId);
}
// 其他必要的方法實(shí)現(xiàn)...
}3.3 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 支持范圍查詢:同一范圍的數(shù)據(jù)存儲(chǔ)在同一分片,范圍查詢效率高
- 數(shù)據(jù)局部性好:相關(guān)數(shù)據(jù)聚集在一起,提高查詢效率
- 易于理解和維護(hù):分片規(guī)則直觀,數(shù)據(jù)分布清晰
缺點(diǎn):
- 數(shù)據(jù)傾斜風(fēng)險(xiǎn):如果數(shù)據(jù)分布不均,可能導(dǎo)致某些分片負(fù)載過重
- 熱點(diǎn)分片問題:新數(shù)據(jù)往往落在最新范圍的分片上,造成訪問熱點(diǎn)
- 分片邊界固定:預(yù)先定義的范圍邊界難以動(dòng)態(tài)調(diào)整
3.4 適用場景
- 時(shí)間序列數(shù)據(jù)或自增ID數(shù)據(jù)的存儲(chǔ)
- 范圍查詢頻繁的應(yīng)用
- 歷史數(shù)據(jù)訪問頻率低但需要保留的系統(tǒng)
- 可以預(yù)測數(shù)據(jù)增長模式的業(yè)務(wù)
四、復(fù)合分片
4.1 原理
復(fù)合分片鍵使用多個(gè)字段的組合作為分片依據(jù),提供更精細(xì)和靈活的分片控制。可以同時(shí)考慮多個(gè)業(yè)務(wù)維度,使分片更貼合業(yè)務(wù)特性。
常見的復(fù)合分片策略包括:
- 多字段哈希組合
- 一級(jí)字段范圍+二級(jí)字段哈希
- 字段組合后再應(yīng)用分片算法
4.2 SpringBoot實(shí)現(xiàn)
使用ShardingSphere-JDBC實(shí)現(xiàn)復(fù)合分片:
spring:
shardingsphere:
datasource:
names: ds0,ds1,ds2,ds3
# 數(shù)據(jù)源配置...
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds${0..3}.t_order
database-strategy:
complex:
sharding-columns: user_id,order_date
sharding-algorithm-name: complex-algorithm
sharding-algorithms:
complex-algorithm:
type: CLASS_BASED
props:
strategy: COMPLEX
algorithmClassName: com.example.CustomComplexShardingAlgorithm自定義復(fù)合分片算法:
@Component
public class CustomComplexShardingAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<?>> {
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames,
ComplexKeysShardingValue<Comparable<?>> shardingValue) {
Map<String, Collection<Comparable<?>>> columnNameAndShardingValuesMap =
shardingValue.getColumnNameAndShardingValuesMap();
Collection<Comparable<?>> userIds = columnNameAndShardingValuesMap.get("user_id");
Collection<Comparable<?>> orderDates = columnNameAndShardingValuesMap.get("order_date");
List<String> result = new ArrayList<>();
for (Comparable<?> userId : userIds) {
for (Comparable<?> orderDate : orderDates) {
// 使用用戶ID和訂單日期的組合確定分片
LocalDate date = (LocalDate) orderDate;
long hash = (long) userId * 31 + date.getYear() * 12 + date.getMonthValue();
int shardingKey = (int) (hash % 4); // 分4個(gè)片
for (String targetName : availableTargetNames) {
if (targetName.endsWith(String.valueOf(shardingKey))) {
result.add(targetName);
}
}
}
}
return result;
}
}實(shí)體類定義:
@Entity
@Table(name = "t_order")
public class Order {
@Id
private Long orderId;
private Long userId; // 復(fù)合分片鍵之一
private LocalDate orderDate; // 復(fù)合分片鍵之一
private BigDecimal amount;
private String status;
// getters and setters
}4.3 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 分片更精細(xì):可以結(jié)合多個(gè)業(yè)務(wù)維度進(jìn)行數(shù)據(jù)分布
- 數(shù)據(jù)分布更均衡:減少單維度分片可能帶來的數(shù)據(jù)傾斜
- 查詢靈活性:支持多種條件的查詢優(yōu)化
- 更貼合業(yè)務(wù):可以根據(jù)實(shí)際業(yè)務(wù)特性定制分片策略
缺點(diǎn):
- 實(shí)現(xiàn)復(fù)雜:需要自定義復(fù)雜的分片算法
- 維護(hù)困難:分片邏輯復(fù)雜,難以理解和維護(hù)
- 查詢成本高:如果查詢條件不包含所有分片鍵,可能需要查詢多個(gè)分片
- 測試難度大:需要全面測試各種查詢場景
4.4 適用場景
單一分片鍵無法滿足均衡性要求的系統(tǒng)
多維度查詢頻繁的應(yīng)用
數(shù)據(jù)有明顯多維度特性的業(yè)務(wù)
需要精細(xì)化控制數(shù)據(jù)分布的場景
五、時(shí)間序列分片
5.1 原理
時(shí)間序列分片鍵使用時(shí)間相關(guān)字段(如創(chuàng)建時(shí)間、交易日期)作為分片依據(jù),通常將特定時(shí)間段的數(shù)據(jù)存儲(chǔ)在同一分片中。
這種方式特別適合具有明顯時(shí)間屬性的數(shù)據(jù),如日志、訂單、交易記錄等。
常見的時(shí)間分片策略包括:
- 按年/月/周/日分片
- 時(shí)間窗口滾動(dòng)分片
- 時(shí)間+其他字段組合分片
5.2 SpringBoot實(shí)現(xiàn)
使用ShardingSphere-JDBC實(shí)現(xiàn)時(shí)間序列分片:
spring:
shardingsphere:
datasource:
names: ds0,ds1,ds2,ds3
# 數(shù)據(jù)源配置...
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds${0..3}.t_order
database-strategy:
standard:
sharding-column: create_time
sharding-algorithm-name: time-sharding
sharding-algorithms:
time-sharding:
type: INTERVAL
props:
datetime-pattern: yyyy-MM-dd HH:mm:ss
datetime-lower: 2023-01-01 00:00:00
datetime-upper: 2023-12-31 23:59:59
sharding-suffix-pattern: yyyyMM
datetime-interval-amount: 3
datetime-interval-unit: MONTHS自定義更復(fù)雜的時(shí)間分片算法:
@Component
public class QuarterlyShardingAlgorithm implements StandardShardingAlgorithm<Date> {
private static final Map<Integer, Integer> QUARTER_MAP = new HashMap<>();
static {
// 將月份映射到季度
QUARTER_MAP.put(1, 1);
QUARTER_MAP.put(2, 1);
QUARTER_MAP.put(3, 1);
QUARTER_MAP.put(4, 2);
QUARTER_MAP.put(5, 2);
QUARTER_MAP.put(6, 2);
QUARTER_MAP.put(7, 3);
QUARTER_MAP.put(8, 3);
QUARTER_MAP.put(9, 3);
QUARTER_MAP.put(10, 4);
QUARTER_MAP.put(11, 4);
QUARTER_MAP.put(12, 4);
}
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> shardingValue) {
Date date = shardingValue.getValue();
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
int quarter = QUARTER_MAP.get(month);
// 將分片策略設(shè)計(jì)為按季度循環(huán)到不同數(shù)據(jù)源
// 例如:2023Q1->ds0, 2023Q2->ds1, 2023Q3->ds2, 2023Q4->ds3, 2024Q1->ds0, ...
int shardIndex = ((year - 2023) * 4 + quarter - 1) % 4;
for (String targetName : availableTargetNames) {
if (targetName.endsWith(String.valueOf(shardIndex))) {
return targetName;
}
}
throw new UnsupportedOperationException("No available target name for date: " + date);
}
// 其他必要的方法實(shí)現(xiàn)...
}實(shí)體類定義:
@Entity
@Table(name = "t_order")
public class Order {
@Id
private Long orderId;
private Long userId;
@Temporal(TemporalType.TIMESTAMP)
private Date createTime; // 時(shí)間分片鍵
private BigDecimal amount;
private String status;
// getters and setters
}5.3 優(yōu)缺點(diǎn)分析
優(yōu)點(diǎn):
- 數(shù)據(jù)生命周期管理:便于實(shí)現(xiàn)數(shù)據(jù)的生命周期管理和歸檔
- 高效的時(shí)間范圍查詢:同一時(shí)間段的數(shù)據(jù)位于同一分片,時(shí)間范圍查詢高效
- 分片擴(kuò)展自然:隨著時(shí)間推移自然擴(kuò)展到新分片
- 冷熱數(shù)據(jù)分離:可以針對(duì)不同時(shí)間段的數(shù)據(jù)采用不同的存儲(chǔ)策略
缺點(diǎn):
- 數(shù)據(jù)分布不均:如果時(shí)間分布不均勻,可能導(dǎo)致分片數(shù)據(jù)量差異大
- 寫入熱點(diǎn)問題:當(dāng)前時(shí)間段的分片成為寫入熱點(diǎn)
- 歷史分片訪問少:舊分片利用率低但仍占用資源
- 跨時(shí)間段查詢復(fù)雜:大范圍的時(shí)間查詢可能需要訪問多個(gè)分片
5.4 適用場景
- 具有明顯時(shí)間屬性和時(shí)間局部性的數(shù)據(jù)
- 日志、訂單、交易等時(shí)間序列數(shù)據(jù)
- 需要定期歸檔歷史數(shù)據(jù)的系統(tǒng)
- 查詢通常限定在特定時(shí)間范圍內(nèi)的應(yīng)用
六、分片策略對(duì)比
6.2 適用場景分析
| 分片類型 | 數(shù)據(jù)分布均衡性 | 查詢效率 | 擴(kuò)展性 | 實(shí)現(xiàn)復(fù)雜度 | 最適合場景 |
| 哈希分片 | 高 | 點(diǎn)查詢高,范圍查詢低 | 中 | 低 | 點(diǎn)查詢?yōu)橹鞯腛LTP系統(tǒng) |
| 范圍分片 | 中低 | 范圍查詢高,點(diǎn)查詢中 | 中 | 中 | 范圍查詢頻繁的系統(tǒng) |
| 復(fù)合分片 | 高 | 多維查詢高,單維查詢中 | 高 | 高 | 多維查詢和復(fù)雜業(yè)務(wù)場景 |
| 時(shí)間序列分片 | 中 | 時(shí)間范圍查詢高 | 高 | 中 | 時(shí)間相關(guān)數(shù)據(jù)和歸檔需求 |
6.3 擴(kuò)容影響分析
| 分片類型 | 增加分片的數(shù)據(jù)遷移量 | 查詢路由改變 | 應(yīng)用改造復(fù)雜度 |
| 哈希分片 | 高(約50%數(shù)據(jù)需遷移) | 大 | 中 |
| 范圍分片 | 低(僅需調(diào)整邊界數(shù)據(jù)) | 小 | 低 |
| 復(fù)合分片 | 中高(取決于算法設(shè)計(jì)) | 中 | 高 |
| 時(shí)間序列分片 | 低(僅影響新數(shù)據(jù)) | 小 | 低 |
七、總結(jié)
在實(shí)際應(yīng)用中,應(yīng)根據(jù)業(yè)務(wù)特點(diǎn)、查詢模式、性能需求和擴(kuò)展預(yù)期來選擇最合適的分片策略。
無論選擇哪種分片策略,都應(yīng)保持分片邏輯的簡潔性和可維護(hù)性,并在系統(tǒng)設(shè)計(jì)初期就考慮未來的擴(kuò)展需求。
通過合理選擇分片鍵,結(jié)合SpringBoot和ShardingSphere等工具,可以構(gòu)建出既滿足業(yè)務(wù)需求又具備良好擴(kuò)展性的應(yīng)用。
到此這篇關(guān)于SpringBoot中4種數(shù)據(jù)水平分片策略的文章就介紹到這了,更多相關(guān)SpringBoot數(shù)據(jù)水平分片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloudGateway?自定義局部過濾器場景分析
這篇文章主要介紹了SpringCloudGateway?自定義局部過濾器場景分析,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2025-06-06
Java NIO Path接口和Files類配合操作文件的實(shí)例
下面小編就為大家分享一篇Java NIO Path接口和Files類配合操作文件的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-11-11
Spring中的@AutoWired與@Resource及@Qualifier注解詳解
這篇文章主要介紹了Spring中的@AutoWired與@Resource及@Qualifier注解詳解,spring不但支持自己定義的@Autowired注解,所以Autowired與Spring是強(qiáng)相關(guān)性,只能在spring框架中使用,而后幾個(gè)注解則不然,需要的朋友可以參考下2023-11-11
Deepin系統(tǒng)安裝eclipse2021-03及CDT插件的安裝教程
本教程教大家deepin20.1操作系統(tǒng)上安裝eclipse_2021-03版的詳細(xì)步驟及CDT插件的安裝方法,通過圖文展示的非常明了,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-06-06

