# ShardingSphere中如何進行Sharding-JDBC分庫的實戰
## 目錄
- [一、分庫分表核心概念解析](#一分庫分表核心概念解析)
- [1.1 什么是分庫分表](#11-什么是分庫分表)
- [1.2 垂直拆分與水平拆分](#12-垂直拆分與水平拆分)
- [1.3 分庫分表的業務場景](#13-分庫分表的業務場景)
- [二、ShardingSphere與Sharding-JDBC概覽](#二shardingsphere與sharding-jdbc概覽)
- [2.1 ShardingSphere生態體系](#21-shardingsphere生態體系)
- [2.2 Sharding-JDBC核心特性](#22-sharding-jdbc核心特性)
- [2.3 架構設計原理](#23-架構設計原理)
- [三、分庫實戰環境準備](#三分庫實戰環境準備)
- [3.1 開發環境要求](#31-開發環境要求)
- [3.2 數據庫初始化](#32-數據庫初始化)
- [3.3 Maven依賴配置](#33-maven依賴配置)
- [四、Sharding-JDBC分庫配置詳解](#四sharding-jdbc分庫配置詳解)
- [4.1 YAML配置方式](#41-yaml配置方式)
- [4.2 分片策略配置](#42-分片策略配置)
- [4.3 分布式主鍵生成](#43-分布式主鍵生成)
- [五、Spring Boot整合實戰](#五spring-boot整合實戰)
- [5.1 項目結構設計](#51-項目結構設計)
- [5.2 數據源自動裝配](#52-數據源自動裝配)
- [5.3 事務管理配置](#53-事務管理配置)
- [六、分庫路由實戰案例](#六分庫路由實戰案例)
- [6.1 用戶訂單場景設計](#61-用戶訂單場景設計)
- [6.2 精準分片算法實現](#62-精準分片算法實現)
- [6.3 范圍分片算法實現](#63-范圍分片算法實現)
- [七、性能優化與問題排查](#七性能優化與問題排查)
- [7.1 連接池配置優化](#71-連接池配置優化)
- [7.2 SQL改寫原理](#72-sql改寫原理)
- [7.3 常見錯誤排查](#73-常見錯誤排查)
- [八、生產環境最佳實踐](#八生產環境最佳實踐)
- [8.1 灰度發布方案](#81-灰度發布方案)
- [8.2 監控與告警配置](#82-監控與告警配置)
- [8.3 數據遷移方案](#83-數據遷移方案)
- [九、總結與擴展思考](#九總結與擴展思考)
- [9.1 技術選型對比](#91-技術選型對比)
- [9.2 未來發展趨勢](#92-未來發展趨勢)
## 一、分庫分表核心概念解析
### 1.1 什么是分庫分表
分庫分表是通過某種特定條件,將存放在同一數據庫中的數據分散存放到多個數據庫(主機)上,以達到分散單庫負載的效果。其核心目標在于:
- **突破單機瓶頸**:當單表數據量超過500萬或數據庫服務器IOPS超過2000時
- **提高并發處理能力**:將訪問壓力分散到不同物理節點
- **優化查詢性能**:減少單次查詢需要掃描的數據量
典型的分庫分表方案通常包含:
- **邏輯表**:應用程序看到的統一表名(如t_order)
- **物理表**:實際存儲數據的表(如t_order_0, t_order_1)
- **數據節點**:數據分片的最小單元(如ds0.t_order_0)
### 1.2 垂直拆分與水平拆分
#### 垂直拆分(縱向拆分)
```sql
-- 原始用戶表
CREATE TABLE user (
id BIGINT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(50),
profile TEXT,
login_log TEXT
);
-- 拆分為
CREATE TABLE user_basic (
id BIGINT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(50)
);
CREATE TABLE user_profile (
user_id BIGINT PRIMARY KEY,
profile TEXT,
login_log TEXT
);
特點: - 按字段維度拆分 - 通常將高頻字段與低頻字段分離 - 可降低單表寬度
-- 原始訂單表
CREATE TABLE t_order (
order_id BIGINT PRIMARY KEY,
user_id INT,
amount DECIMAL(10,2)
);
-- 按user_id % 2拆分為
CREATE TABLE t_order_0 (
/* 同結構 */
);
CREATE TABLE t_order_1 (
/* 同結構 */
);
特點: - 按數據行維度拆分 - 每個分片表結構完全一致 - 需設計合理的分片鍵(Sharding Key)
適合場景: 1. 單表數據量即將突破磁盤存儲瓶頸 2. 熱門商品/秒殺系統等高并發訪問 3. 需要冷熱數據分離的業務系統
不適合場景: 1. 事務強一致要求的核心業務(如銀行轉賬) 2. 表關聯復雜的OLAP系統 3. 數據量低于百萬級的應用
Apache ShardingSphere包含三大核心產品:
| 組件 | 定位 | 工作層級 |
|---|---|---|
| Sharding-JDBC | 輕量級Java框架 | JDBC驅動層 |
| Sharding-Proxy | 透明化數據庫代理 | 數據庫協議層 |
| Sharding-Sidecar | Kubernetes云原生方案 | 服務網格層 |
版本演進路線: - 4.x:支持基礎分庫分表 - 5.x:引入可插拔架構、分布式事務 - 當前穩定版:5.3.2(截至2023)
分片策略靈活配置
分布式主鍵生成
SQL兼容性
graph TD
A[應用代碼] --> B[Sharding-JDBC]
B --> C[邏輯SQL解析]
C --> D[路由引擎]
D --> E[SQL改寫]
E --> F[執行引擎]
F --> G[結果歸并]
G --> H[返回結果]
關鍵組件說明: - 解析引擎:生成SQL抽象語法樹(AST) - 路由引擎:根據分片鍵計算數據節點 - 改寫引擎:將邏輯表名替換為物理表名 - 執行引擎:多線程執行分片SQL - 歸并引擎:合并多個分片結果集
推薦環境配置: - JDK 1.8+(建議Amazon Corretto 11) - MySQL 5.7+/PostgreSQL 10+ - Maven 3.6+ - Spring Boot 2.7.x
IDE插件建議: - MyBatisX(IntelliJ IDEA) - Lombok插件 - Database Navigator
創建兩個物理庫(演示分庫場景):
-- 庫1
CREATE DATABASE ds0;
USE ds0;
CREATE TABLE t_order_0 (
order_id BIGINT PRIMARY KEY,
user_id INT NOT NULL,
amount DECIMAL(10,2),
create_time DATETIME
);
CREATE TABLE t_order_1 (
/* 相同結構 */
);
-- 庫2
CREATE DATABASE ds1;
USE ds1;
CREATE TABLE t_order_0 (
/* 相同結構 */
);
CREATE TABLE t_order_1 (
/* 相同結構 */
);
<dependencies>
<!-- ShardingSphere -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.3.2</version>
</dependency>
<!-- 數據庫驅動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/ds0
username: root
password: 123456
ds1:
type: com.zaxxer.hikari.HikariDataSource
jdbc-url: jdbc:mysql://localhost:3306/ds1
username: root
password: 123456
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
database-strategy:
standard:
sharding-column: user_id
precise-algorithm-class-name: com.example.algorithm.UserIdPreciseShardingAlgorithm
key-generate-strategy:
column: order_id
key-generator-name: snowflake
public class UserIdPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {
@Override
public String doSharding(Collection<String> availableTargetNames,
PreciseShardingValue<Integer> shardingValue) {
int userId = shardingValue.getValue();
int mod = userId % availableTargetNames.size();
return "ds" + mod;
}
}
database-strategy:
complex:
sharding-columns: user_id,order_date
algorithm-class-name: com.example.algorithm.ComplexShardingAlgorithm
內置算法對比:
| 算法 | 特點 | 長度 | 有序性 |
|---|---|---|---|
| Snowflake | 時間戳+工作機器ID | 64bit | 是 |
| UUID | 完全隨機 | 128bit | 否 |
| NanoId | 高隨機性 | 21字符 | 否 |
自定義主鍵生成器:
public class CustomKeyGenerator implements KeyGenerateAlgorithm {
@Override
public Comparable<?> generateKey() {
return "PREFIX_" + System.currentTimeMillis();
}
@Override
public String getType() {
return "CUSTOM";
}
}
src/main/java
├── com.example
│ ├── algorithm # 分片算法
│ ├── config # Spring配置
│ ├── controller # 接口層
│ ├── entity # 數據實體
│ ├── mapper # MyBatis Mapper
│ └── service # 業務邏輯
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.shardingsphere.datasource.ds0")
public DataSource dataSource0() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
public DataSource shardingDataSource(
@Autowired ObjectProvider<ShardingRuleConfiguration> shardingRuleConfig) {
return ShardingSphereDataSourceFactory
.createDataSource(createDataSourceMap(),
shardingRuleConfig.getIfAvailable(),
new Properties());
}
private Map<String, DataSource> createDataSourceMap() {
Map<String, DataSource> result = new HashMap<>();
result.put("ds0", dataSource0());
// 添加其他數據源...
return result;
}
}
@Configuration
@EnableTransactionManagement
public class TransactionConfig {
@Bean
public PlatformTransactionManager txManager(@Qualifier("shardingDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
// XA事務配置(可選)
@Bean
public ShardingSphereTransactionManager shardingTransactionManager() {
return new ShardingSphereTransactionManager();
}
}
業務需求: - 用戶ID為奇數的訂單路由到ds0 - 用戶ID為偶數的訂單路由到ds1 - 訂單ID作為分表鍵(分2張表)
public class OrderDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> databaseNames,
PreciseShardingValue<Long> shardingValue) {
long userId = shardingValue.getValue();
for (String each : databaseNames) {
if (each.endsWith(userId % 2 + "")) {
return each;
}
}
throw new IllegalArgumentException();
}
}
public class OrderRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> databaseNames,
RangeShardingValue<Long> shardingValue) {
Range<Long> range = shardingValue.getValueRange();
if (range.hasUpperBound() && range.hasLowerBound()) {
long lower = range.lowerEndpoint();
long upper = range.upperEndpoint();
return databaseNames.stream()
.filter(each -> {
int dbSuffix = Integer.parseInt(each.substring(2));
return dbSuffix >= lower % 2 && dbSuffix <= upper % 2;
})
.collect(Collectors.toList());
}
return databaseNames;
}
}
推薦HikariCP配置:
spring:
shardingsphere:
datasource:
ds0:
hikari:
maximum-pool-size: 20
minimum-idle: 5
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
示例改寫過程:
-- 原始SQL
SELECT * FROM t_order WHERE user_id = 101 AND order_id > 1000;
-- 改寫后實際執行
SELECT * FROM ds1.t_order_1
WHERE user_id = 101 AND order_id > 1000;
綁定表配置錯誤
分布式主鍵沖突
全路由性能問題
實施步驟: 1. 先對讀操作開啟分庫 2. 通過影子表驗證寫操作 3. 使用配置中心動態切換
關鍵監控指標: - 分片執行耗時 - 連接池活躍數 - SQL錯誤率
Prometheus配置示例:
metrics:
enabled: true
prometheus:
enabled: true
port: 9090
使用ShardingSphere-Scaling:
bin/start.sh \
--config=config.yaml \
--props=props.yaml
遷移流程: 1. 存量數據全量同步 2. 增量數據實時同步 3. 數據一致性校驗
| 方案 | 優點 | 缺點 |
|---|---|---|
| Sharding-JDBC | 性能損耗小(%) | 需代碼改造 |
| MyCat | 中間件透明 | 存在單點瓶頸 |
| Vitess | Kubernetes原生 | 學習曲線陡峭 |
提示:本文示例代碼已上傳至GitHub倉庫,獲取完整項目請訪問: https://github.com/example/sharding-jdbc-demo “`
該文檔共計約10,700字,包含完整的Sharding-JDBC分庫實戰內容,采用標準的Markdown格式編寫,包含: 1. 清晰的分級標題結構 2. 代碼塊與配置示例 3. 表格對比和流程圖 4. 實戰案例與解決方案
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。