Apache ShardingSphere 快速集成使用配置教程
本教程基于 Apache ShardingSphere 5.5.3(2026 年 3 月 1 日发布)编写,面向初次接触 ShardingSphere 的开发者,从核心概念到实战配置逐步展开。
一、认识 Apache ShardingSphere
Apache ShardingSphere 是一款分布式的数据库生态系统,能够将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。它于 2020 年 4 月成为 Apache 软件基金会顶级项目,采用 Database Plus 设计哲学——不重新造一个数据库,而是在异构数据库上层构建标准和生态,关注数据库之间的协作而非数据库自身。
核心功能一览
| 功能 | 作用 |
|---|---|
| 数据分片 | 应对海量数据存储与计算,水平扩展计算和存储能力 |
| 分布式事务 | 基于 XA 和 BASE 混合事务引擎,保证跨数据源数据安全 |
| 读写分离 | 灵活拆分读写流量并提供读流量负载均衡 |
| 数据迁移 | 提供跨数据源数据迁移能力,支持重分片扩展 |
| 联邦查询 | 跨数据源复杂查询分析,实现跨源数据关联与聚合 |
| 数据加密 | 完整、透明、安全、低成本的加密解决方案 |
| 影子库 | 全链路压测场景下数据隔离,避免测试数据污染生产环境 |
5.5.3 版本关键变化
5.5.3 是目前最新的稳定版本,历时数月开发,合并了来自全球 54 位 Contributor 的 3,330 个 Commit,变更超过 60 万行代码。主要亮点包括:
- 可插拔 BOM:功能模块(Feature)、数据库类型(DB)、注册中心类型(Registry Center)完全解耦为可插拔插件,应用只需引入核心依赖再按需添加"积木模块"
- JDBC URL 极致简化:只需在 JDBC URL 中提供注册中心地址即可完成数据源初始化,替代本地 YAML 配置
- SQL 兼容度提升:深度强化 MySQL 存储过程及复杂函数语法解析,提升对 Doris、Hive 等分析型数据库的兼容度
- Firebird 生态支持:正式支持 Firebird 数据库代理
- 安全加固:集中修复 8 组共 20 个 CVE 漏洞
- JDK 支持:支持在 OpenJDK 24 和 25 环境下编译运行,JDBC URL 支持 IPv6 协议
二、核心架构与概念
三层可插拔架构
ShardingSphere 的架构划分为三层,各层职责清晰、互不耦合:
graph TB
subgraph L3["L3 生态层"]
A1["数据库协议<br/>MySQL / PostgreSQL / Firebird"]
A2["SQL 解析器<br/>方言适配"]
A3["存储适配器<br/>对接各类数据库"]
end
subgraph L2["L2 功能层 - 可选"]
B1["数据分片"]
B2["读写分离"]
B3["数据加密"]
B4["影子库"]
B5["数据脱敏"]
end
subgraph L1["L1 内核层 - 必须"]
C1["查询优化器"]
C2["分布式事务引擎"]
C3["分布式执行引擎"]
C4["权限引擎"]
C5["调度引擎"]
end
L3 --> L2 --> L1
- L1 内核层:数据库基本能力的抽象,所有组件必须存在,但实现方式可通过可插拔方式更换
- L2 功能层:提供增量能力,组件完全隔离、互无感知,多组件可叠加使用,用户可自定义扩展
- L3 生态层:对接现有数据库生态,包括数据库协议、SQL 解析器和存储适配器
两种部署形态
ShardingSphere 提供两款既可独立部署又可混合使用的产品:
graph LR
subgraph JDBC["ShardingSphere-JDBC"]
J1["Java 应用"] --> J2["ShardingSphere-JDBC<br/>(JAR 包)"]
J2 --> J3["数据库"]
end
subgraph Proxy["ShardingSphere-Proxy"]
P1["任意语言应用"] --> P2["ShardingSphere-Proxy<br/>(独立服务进程)"]
P2 --> P3["数据库"]
P2 --> P4["数据库"]
end
| 对比维度 | ShardingSphere-JDBC | ShardingSphere-Proxy |
|---|---|---|
| 数据库支持 | 任意(通过 JDBC 访问的数据库) | MySQL / PostgreSQL / Firebird |
| 连接消耗 | 高(每个应用实例各自建连) | 低(统一连接池) |
| 异构语言 | 仅 Java | 任意语言 |
| 性能 | 损耗低(直连数据库) | 损耗略高(多一跳网络 IO) |
| 无中心化 | 是 | 否 |
| 静态入口 | 无 | 有(固定连接地址) |
选择建议:Java 高性能 OLTP 应用优先用 JDBC;异构语言、OLAP 场景或 DBA 运维管理用 Proxy;复杂场景可混合部署,JDBC 处理 OLTP,Proxy 处理 OLAP 和运维。
关键术语
- 逻辑表:相同结构的水平拆分表的逻辑名称。例如
t_user_0到t_user_9的逻辑表名为t_user - 真实表:在水平拆分数据库中真实存在的物理表,如
t_user_0 - 数据节点:数据分片的最小单元,由数据源名和真实表组成,如
ds_0.t_user_0 - 绑定表:分片规则一致的主表和子表,关联查询时走同路由避免笛卡尔积
- 广播表:所有库中都存在的表,写入时同时写入多个库,查询时随机读一个
三、快速开始:ShardingSphere-JDBC
ShardingSphere-JDBC 定位为轻量级 Java 框架,以 JAR 包形式提供服务,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
3.1 工作原理
sequenceDiagram
participant App as 应用程序
participant SS as ShardingSphere-JDBC
participant DB0 as 数据库 ds_0
participant DB1 as 数据库 ds_1
App->>SS: 发送 SQL(操作逻辑表)
SS->>SS: SQL 解析(Parse)
SS->>SS: SQL 路由(Route)— 根据分片键计算目标节点
SS->>SS: SQL 改写(Rewrite)— 逻辑表替换为真实表
SS->>DB0: 执行 SQL(真实表)
SS->>DB1: 执行 SQL(真实表)
DB0-->>SS: 返回结果
DB1-->>SS: 返回结果
SS->>SS: 结果归并(Merge)
SS-->>App: 返回归并后的结果集
3.2 环境准备
- JDK 17+(5.5.3 支持 OpenJDK 24/25)
- Maven 3.6+
- MySQL 8.0+
- Spring Boot 3.x(本教程示例)
先创建两个数据库和对应的分表:
-- 创建数据库
CREATE DATABASE shardingdb0;
CREATE DATABASE shardingdb1;
-- 在 shardingdb0 中创建分表
USE shardingdb0;
CREATE TABLE t_order_0 (
order_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2),
status VARCHAR(20),
PRIMARY KEY (order_id)
);
CREATE TABLE t_order_1 (
order_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2),
status VARCHAR(20),
PRIMARY KEY (order_id)
);
-- 在 shardingdb1 中创建相同的分表
USE shardingdb1;
CREATE TABLE t_order_0 (
order_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2),
status VARCHAR(20),
PRIMARY KEY (order_id)
);
CREATE TABLE t_order_1 (
order_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2),
status VARCHAR(20),
PRIMARY KEY (order_id)
);
3.3 添加 Maven 依赖
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- ShardingSphere JDBC 核心依赖 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc</artifactId>
<version>5.5.3</version>
</dependency>
<!-- 连接池 HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!-- MyBatis Plus(可选,本教程示例使用) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.12</version>
</dependency>
5.5.3 引入了 BOM(Bill of Materials)统一版本基线,开发者只需引入核心依赖,再按需添加具体功能模块。如果想统一管理 ShardingSphere 全家桶版本,可以在
dependencyManagement中引入 BOM:<dependencyManagement> <dependencies> <dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>shardingsphere-bom</artifactId> <version>5.5.3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
3.4 配置数据源
在 Spring Boot 的 application.yml 中配置 ShardingSphere 驱动:
spring:
datasource:
driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
# 指向类路径下的分片配置文件
url: jdbc:shardingsphere:classpath:sharding.yaml
5.5.3 的新特性:如果使用集群模式并接入了 ZooKeeper 或 ETCD 注册中心,JDBC URL 可以直接写注册中心地址,无需本地 YAML 文件:
# ZooKeeper 方式 url: jdbc:shardingsphere:zk://127.0.0.1:2181/sharding_sphere_config # ETCD 方式 url: jdbc:shardingsphere:etcd://127.0.0.1:2379/sharding_sphere_config
也可以通过 Java 配置类创建数据源(适用于多数据源场景):
@Configuration
public class DataSourceConfig {
@Bean(name = "shardingDataSource")
public DataSource shardingDataSource() throws SQLException, IOException {
try (InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("sharding.yaml")) {
if (inputStream == null) {
throw new IllegalStateException("Cannot find sharding.yaml in classpath");
}
byte[] yamlBytes = inputStream.readAllBytes();
return YamlShardingSphereDataSourceFactory.createDataSource(yamlBytes);
}
}
}
3.5 编写分片配置
在 src/main/resources/sharding.yaml 中编写分片规则:
# ==================== 数据源配置 ====================
dataSources:
ds_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://127.0.0.1:3306/shardingdb0?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
username: root
password: your_password
ds_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://127.0.0.1:3306/shardingdb1?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
username: root
password: your_password
# ==================== 分片规则 ====================
rules:
- !SHARDING
tables:
t_order: # 逻辑表名
actualDataNodes: ds_${0..1}.t_order_${0..1} # 实际数据节点:2库 x 2表
databaseStrategy: # 分库策略
standard: # 单分片键标准分片
shardingColumn: user_id # 分片列
shardingAlgorithmName: db_inline # 分片算法名称
tableStrategy: # 分表策略
standard:
shardingColumn: order_id # 分片列
shardingAlgorithmName: t_order_inline
keyGenerateStrategy: # 分布式主键策略
column: order_id # 自增列
keyGeneratorName: snowflake # 主键生成器
# 绑定表:主子表分片规则一致,关联查询走同路由
t_order_item:
actualDataNodes: ds_${0..1}.t_order_item_${0..1}
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: db_inline
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: t_order_inline
keyGenerateStrategy:
column: item_id
keyGeneratorName: snowflake
bindingTables: # 绑定表声明
- t_order,t_order_item
# 分片算法定义
shardingAlgorithms:
db_inline: # 分库算法:user_id 取模
type: INLINE
props:
algorithm-expression: ds_${user_id % 2}
allow-range-query-with-inline-sharding: true # 允许范围查询
t_order_inline: # 分表算法:order_id 取模
type: INLINE
props:
algorithm-expression: t_order_${order_id % 2}
# 主键生成器定义
keyGenerators:
snowflake: # 雪花算法(Long 类型)
type: SNOWFLAKE
# ==================== 属性配置 ====================
props:
sql-show: true # 打印改写后的真实 SQL,便于调试
check-table-metadata-enabled: false # 启动时不检查分片元数据一致性
3.6 配置项说明
配置文件由三大块组成,结构如下:
graph TD
A["sharding.yaml"] --> B["dataSources<br/>数据源配置"]
A --> C["rules<br/>规则配置"]
A --> D["props<br/>属性配置"]
B --> B1["ds_0 / ds_1<br/>物理数据源"]
C --> C1["!SHARDING<br/>分片规则"]
C --> C2["!READWRITE_SPLITTING<br/>读写分离"]
C --> C3["!ENCRYPT<br/>数据加密"]
C --> C4["!BROADCAST<br/>广播表"]
C --> C5["!SINGLE<br/>单表规则"]
C --> C6["!MASK<br/>数据脱敏"]
D --> D1["sql-show<br/>SQL 日志"]
D --> D2["check-table-metadata-enabled<br/>元数据检查"]
分片策略类型对照:
| 策略类型 | 配置关键字 | 适用场景 |
|---|---|---|
| 标准分片 | standard |
单分片键,精确分片 + 可选范围分片 |
| 复合分片 | complex |
多分片键组合分片 |
| Hint 分片 | hint |
不通过 SQL 而通过程序指定分片 |
| 自动分片 | autoTables |
只指定数据源和算法,自动分配数据节点 |
内置分片算法:
| 算法类型 | type 值 | 说明 |
|---|---|---|
| 行表达式分片 | INLINE |
基于 Groovy 表达式,最常用 |
| 取模分片 | MOD |
基于取模运算 |
| 哈希取模分片 | HASH_MOD |
先对分片键哈希再取模 |
| 范围分片 | INTERVAL |
基于时间或数值范围分片 |
| 自定义分片 | CLASS_BASED |
通过实现接口自定义算法 |
主键生成器类型:
| 类型 | type 值 | 生成的主键类型 |
|---|---|---|
| 雪花算法 | SNOWFLAKE |
Long |
| UUID | UUID |
String(带连字符) |
| NanoID | NANOID |
String |
3.7 代码实战
定义实体和 Mapper:
@Data
@TableName("t_order")
public class Order {
@TableId(type = IdType.ASSIGN_ID) // 使用 ShardingSphere 生成主键
private Long orderId;
private Long userId;
private BigDecimal amount;
private String status;
}
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
编写测试代码:
@SpringBootTest
public class ShardingTest {
@Autowired
private OrderMapper orderMapper;
@Test
void testInsert() {
for (long i = 1; i <= 10; i++) {
Order order = new Order();
order.setUserId(i); // 分库键
order.setAmount(new BigDecimal("100.00"));
order.setStatus("INIT");
orderMapper.insert(order); // order_id 由雪花算法自动生成
}
}
@Test
void testQuery() {
// 精确查询:根据分片键路由到单库单表
LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Order::getUserId, 1L);
List<Order> orders = orderMapper.selectList(wrapper);
orders.forEach(System.out::println);
}
@Test
void testQueryAll() {
// 无分片键查询:全路由,归并结果
List<Order> orders = orderMapper.selectList(null);
orders.forEach(System.out::println);
}
}
由于配置了 sql-show: true,控制台会打印路由后的真实 SQL,方便调试:
[ShardingSphere-SQL] Actual SQL: ds_0 ::: INSERT INTO t_order_0 (order_id, user_id, amount, status) VALUES (?, ?, ?, ?)
[ShardingSphere-SQL] Actual SQL: ds_1 ::: INSERT INTO t_order_1 (order_id, user_id, amount, status) VALUES (?, ?, ?, ?)
四、快速开始:ShardingSphere-Proxy
ShardingSphere-Proxy 是一个独立的服务进程,通过实现数据库二进制协议,将自己伪装成 MySQL/PostgreSQL 数据库,对客户端完全透明。
4.1 工作原理
sequenceDiagram
participant Client as 客户端<br/>(MySQL CLI / Navicat / 应用)
participant Proxy as ShardingSphere-Proxy<br/>(端口 3307)
participant DB0 as MySQL ds_0
participant DB1 as MySQL ds_1
Client->>Proxy: MySQL 协议连接(以为是 MySQL)
Client->>Proxy: SELECT * FROM t_order WHERE user_id=1
Proxy->>Proxy: 解析 SQL + 路由计算
Proxy->>DB0: SELECT * FROM t_order_0 WHERE user_id=1
Proxy->>DB1: SELECT * FROM t_order_1 WHERE user_id=1
DB0-->>Proxy: 结果集
DB1-->>Proxy: 结果集
Proxy->>Proxy: 结果归并
Proxy-->>Client: 返回归并结果(MySQL 协议)
4.2 下载与安装
从官方下载页面获取二进制安装包:
https://shardingsphere.apache.org/document/5.5.3/cn/downloads/
解压后的目录结构:
shardingsphere-proxy-bin/
├── LICENSE
├── NOTICE
├── README.txt
├── bin/ # 启动停止脚本
├── conf/ # 配置文件目录
├── lib/ # JAR 包
└── licenses/
需要手动创建 ext-lib 目录并放入 MySQL JDBC 驱动:
mkdir ext-lib
# 下载 MySQL 驱动到 ext-lib 目录
wget -O ext-lib/mysql-connector-j-8.0.33.jar \
https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.0.33/mysql-connector-j-8.0.33.jar
4.3 配置 server.yaml
conf/server.yaml 是 Proxy 的全局配置,包含运行模式、认证信息、事务类型等:
mode:
type: Standalone # 单机模式(生产环境用 Cluster)
repository:
type: JDBC # 元数据持久化方式
props:
provider: H2
jdbc_url: jdbc:h2:mem:config;DB_CLOSE_DELAY=-1;MODE=MySQL
rules:
- !AUTHORITY # 认证配置
users:
- root@%:root # 用户名:密码,% 表示任意主机
- sharding@:sharding
provider:
type: ALL_PERMITTED # 权限策略:全部允许(生产环境应细化)
- !TRANSACTION # 事务配置
defaultType: XA # 默认事务类型:XA / BASE
providerType: Atomikos # XA 事务管理器
- !SQL_PARSER # SQL 解析器缓存配置
sqlStatementCache:
initialCapacity: 2000
maximumSize: 65535
parseTreeCache:
initialCapacity: 128
maximumSize: 1024
props:
max-connections-size-per-query: 1 # 单次查询最大连接数
kernel-executor-size: 16 # 内核执行线程数
proxy-frontend-flush-threshold: 128 # 前端刷新阈值
sql-show: false # 是否打印真实 SQL
proxy-frontend-max-connections: 0 # 最大前端连接数(0=不限制)
proxy-backend-executor-suitable: OLAP # 后端执行器类型:OLAP / OLTP
4.4 配置分片规则
conf/config-sharding.yaml 定义逻辑库和分片规则:
schemaName: sharding_db # 逻辑库名称(客户端看到的数据库名)
dataSources: # 物理数据源
ds_0:
url: jdbc:mysql://127.0.0.1:3306/shardingdb0?serverTimezone=UTC&useSSL=false
username: root
password: your_password
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
ds_1:
url: jdbc:mysql://127.0.0.1:3306/shardingdb1?serverTimezone=UTC&useSSL=false
username: root
password: your_password
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 50
minPoolSize: 1
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: ds_${0..1}.t_order_${0..1}
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: database_inline
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: t_order_inline
keyGenerateStrategy:
column: order_id
keyGeneratorName: snowflake
shardingAlgorithms:
database_inline:
type: INLINE
props:
algorithm-expression: ds_${user_id % 2}
t_order_inline:
type: INLINE
props:
algorithm-expression: t_order_${order_id % 2}
keyGenerators:
snowflake:
type: SNOWFLAKE
4.5 启动与连接
# Linux / macOS 启动
sh bin/start.sh
# 指定端口启动(默认 3307)
sh bin/start.sh 3308
# Windows 启动
bin/start.bat
# 查看启动日志
tail -100f logs/stdout.log
看到以下日志表示启动成功:
[INFO ] 2026-xx-xx xx:xx:xx.xxx [main] o.a.s.p.frontend.ShardingSphereProxy
- ShardingSphere-Proxy Standalone mode started successfully
使用 MySQL 客户端连接:
mysql -h 127.0.0.1 -u root -proot -P 3307
连接后操作逻辑库和逻辑表,ShardingSphere 会自动路由到真实的物理表:
mysql> SHOW DATABASES;
+-------------+
| schema_name |
+-------------+
| sharding_db |
+-------------+
mysql> USE sharding_db;
-- 插入数据,ShardingSphere 自动路由到对应分表
mysql> INSERT INTO t_order (user_id, amount, status) VALUES
(1, 100.00, 'INIT'),
(2, 200.00, 'INIT'),
(3, 300.00, 'INIT');
-- 查询时透明聚合所有分表
mysql> SELECT * FROM t_order WHERE user_id = 1;
+--------------------+---------+--------+--------+
| order_id | user_id | amount | status |
+--------------------+---------+--------+--------+
| 786812345678901234 | 1 | 100.00 | INIT |
+--------------------+---------+--------+--------+
4.6 Docker 部署
docker run -d \
--name shardingsphere-proxy \
-p 3307:3307 \
-v /path/to/conf:/opt/shardingsphere-proxy/conf \
-v /path/to/ext-lib:/opt/shardingsphere-proxy/ext-lib \
apache/shardingsphere-proxy:5.5.3
五、核心功能配置详解
5.1 读写分离
读写分离将写请求路由到主库,读请求按负载均衡策略路由到从库,是应对高并发读访问的常见手段。
graph LR
App["应用"] --> SS["ShardingSphere"]
SS -->|写请求| Write["主库 write_ds"]
SS -->|读请求| LB["负载均衡"]
LB -->|轮询/随机| Read0["从库 read_ds_0"]
LB -->|轮询/随机| Read1["从库 read_ds_1"]
配置示例:
rules:
- !READWRITE_SPLITTING
dataSourceGroups:
readwrite_ds: # 读写分离逻辑数据源名称
writeDataSourceName: write_ds # 写库(主库)数据源名
readDataSourceNames: # 读库(从库)数据源名列表
- read_ds_0
- read_ds_1
transactionalReadQueryStrategy: PRIMARY # 事务内读请求路由策略
loadBalancerName: random # 负载均衡算法名称
loadBalancers:
random: # 随机负载均衡
type: RANDOM
round_robin: # 轮询负载均衡
type: ROUND_ROBIN
weight: # 权重负载均衡
type: WEIGHT
props:
read_ds_0: 2 # 权重值
read_ds_1: 1
事务内读请求路由策略(transactionalReadQueryStrategy):
| 策略值 | 行为 | 适用场景 |
|---|---|---|
PRIMARY |
事务内读请求路由到主库 | 默认值,保证读写一致性 |
FIXED |
同一事务内路由至固定数据源 | 需数据库支持主从强一致同步 |
DYNAMIC |
同一事务内路由至非固定数据源 | 需数据库支持主从强一致同步 |
5.2 分片 + 读写分离组合
实际生产中常需要同时使用分片和读写分离。配置时在分片规则中引用读写分离逻辑数据源即可:
dataSources:
# 主库
write_ds_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://127.0.0.1:3306/master_0
# ... 其他连接参数
write_ds_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://127.0.0.1:3306/master_1
# 从库
read_ds_0_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://127.0.0.1:3307/slave_0_0
read_ds_0_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://127.0.0.1:3308/slave_0_1
read_ds_1_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://127.0.0.1:3307/slave_1_0
read_ds_1_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://127.0.0.1:3308/slave_1_1
rules:
- !READWRITE_SPLITTING
dataSourceGroups:
ds_0: # 逻辑数据源 ds_0 = 1主2从
writeDataSourceName: write_ds_0
readDataSourceNames: [read_ds_0_0, read_ds_0_1]
loadBalancerName: round_robin
ds_1: # 逻辑数据源 ds_1 = 1主2从
writeDataSourceName: write_ds_1
readDataSourceNames: [read_ds_1_0, read_ds_1_1]
loadBalancerName: round_robin
loadBalancers:
round_robin:
type: ROUND_ROBIN
- !SHARDING
tables:
t_order:
actualDataNodes: ds_${0..1}.t_order_${0..1} # ds_0/ds_1 是读写分离逻辑数据源
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: db_inline
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: t_order_inline
shardingAlgorithms:
db_inline:
type: INLINE
props:
algorithm-expression: ds_${user_id % 2}
t_order_inline:
type: INLINE
props:
algorithm-expression: t_order_${order_id % 2}
组合后的数据流向:
graph TD
App["应用"] --> SS["ShardingSphere"]
SS -->|写 user_id=1| W0["ds_0 主库 write_ds_0"]
SS -->|读 user_id=1| R0["ds_0 从库<br/>read_ds_0_0 或 read_ds_0_1"]
SS -->|写 user_id=2| W1["ds_1 主库 write_ds_1"]
SS -->|读 user_id=2| R1["ds_1 从库<br/>read_ds_1_0 或 read_ds_1_1"]
5.3 分布式事务
ShardingSphere 提供两种分布式事务方案:
| 事务类型 | 一致性 | 性能 | 适用场景 |
|---|---|---|---|
| XA 事务 | 强一致 | 较低 | 对数据一致性要求高的场景 |
| BASE 事务 | 最终一致 | 较高 | 对性能要求高、可容忍短暂不一致 |
XA 事务配置(JDBC 端):
rules:
- !TRANSACTION
defaultType: XA
providerType: Atomikos # XA 事务管理器:Atomikos / Narayana
引入事务管理器依赖:
<!-- XA 事务管理器 Atomikos -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-transaction-xa-atomikos</artifactId>
<version>5.5.3</version>
</dependency>
BASE 事务配置(需要 Seata):
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-transaction-base-seata-at</artifactId>
<version>5.5.3</version>
</dependency>
rules:
- !TRANSACTION
defaultType: BASE
providerType: Seata
代码中使用注解切换事务类型:
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderItemMapper orderItemMapper;
// 使用默认事务类型(配置文件中指定的)
@Transactional
public void createOrder(Order order, OrderItem item) {
orderMapper.insert(order); // 可能路由到 ds_0
orderItemMapper.insert(item); // 可能路由到 ds_1
// 跨库操作,由分布式事务保证一致性
}
// 显式指定 XA 事务
@ShardingSphereTransactionType(TransactionType.XA)
@Transactional
public void createOrderWithXA(Order order, OrderItem item) {
orderMapper.insert(order);
orderItemMapper.insert(item);
}
// 显式指定 BASE 事务
@ShardingSphereTransactionType(TransactionType.BASE)
@Transactional
public void createOrderWithBASE(Order order, OrderItem item) {
orderMapper.insert(order);
orderItemMapper.insert(item);
}
}
5.4 数据加密
数据加密对应用透明:写入时自动加密存储,读取时自动解密返回,应用层无需感知。
graph LR
subgraph 写入流程
W1["应用写入明文"] --> W2["ShardingSphere 加密"] --> W3["数据库存储密文"]
end
subgraph 读取流程
R1["数据库返回密文"] --> R2["ShardingSphere 解密"] --> R3["应用获取明文"]
end
配置示例:
rules:
- !ENCRYPT
tables:
t_user: # 加密表
columns:
password: # 加密列(逻辑列名)
cipher:
name: password # 密文列名(物理存储列)
encryptorName: aes_encryptor # 加密算法
phone:
cipher:
name: phone_cipher
encryptorName: aes_encryptor
assistedQuery: # 辅助查询列(用于等值查询)
name: phone_assisted
encryptorName: md5_assisted
encryptors: # 加密算法定义
aes_encryptor:
type: AES
props:
aes-key-value: 123456abc # AES 密钥
digest-algorithm-name: SHA-1 # 密钥摘要算法
md5_assisted: # 辅助查询加密算法(不可逆)
type: MD5
应用代码无需任何改动,正常写入和查询即可:
// 写入时,ShardingSphere 自动将 password 加密后存储
userMapper.insert(user); // user.password = "明文密码"
// 查询时,ShardingSphere 自动解密返回明文
User user = userMapper.selectById(1L); // user.password = "明文密码"
// 等值查询时,ShardingSphere 自动加密查询条件
wrapper.eq(User::getPhone, "13800138000");
// 实际执行:WHERE phone_cipher = AES('13800138000')
// AND phone_assisted = MD5('13800138000')
5.5 数据脱敏
数据脱敏用于在查询结果中对敏感数据进行掩码处理,常用于日志展示、数据导出等场景:
rules:
- !MASK
tables:
t_user:
columns:
email:
maskAlgorithm: mask_before_at # 邮箱脱敏
phone:
maskAlgorithm: keep_first_last # 手机号脱敏
id_card:
maskAlgorithm: mask_middle # 身份证脱敏
maskAlgorithms:
mask_before_at: # @ 前部分脱敏
type: MASK_BEFORE_SPECIAL_CHARS
props:
special-chars: '@'
replace-char: '*'
keep_first_last: # 保留前3后4
type: KEEP_FIRST_N_LAST_M
props:
first-n: 3
last-m: 4
replace-char: '*'
mask_middle: # 中间脱敏
type: MASK_FROM_MIDDLE_TO_HEAD
props:
replace-char: '*'
target-chars: '8'
脱敏效果示例:
| 原始数据 | 脱敏算法 | 脱敏结果 |
|---|---|---|
zhangsan@qq.com |
MASK_BEFORE_SPECIAL_CHARS | ********@qq.com |
13812345678 |
KEEP_FIRST_N_LAST_M (3,4) | 138****5678 |
110101199001011234 |
MASK_FROM_MIDDLE_TO_HEAD | **********001234 |
5.6 广播表与单表
广播表:所有库中都存在的表,写入时同时写入多个库,查询时随机读一个。适用于字典表、配置表等数据量小但需要频繁 JOIN 的表:
rules:
- !BROADCAST
tables:
- t_dict # 字典表
- t_config # 配置表
单表:不需要分库分表的普通表,需要显式声明其所在数据源:
rules:
- !SINGLE
tables:
- ds_0.t_address # 指定单表
# - ds_1.* # 加载 ds_1 所有单表
# - "*.*" # 加载所有单表(谨慎使用)
六、运行模式与生产部署
6.1 单机模式 vs 集群模式
graph TB
subgraph Standalone["单机模式"]
S1["ShardingSphere 实例"] --> S2["本地元数据存储<br/>(H2 文件)"]
end
subgraph Cluster["集群模式"]
C1["ShardingSphere 实例 1"]
C2["ShardingSphere 实例 2"]
C3["ShardingSphere 实例 N"]
C1 --> ZK["注册中心<br/>ZooKeeper / ETCD"]
C2 --> ZK
C3 --> ZK
ZK --> M["元数据共享<br/>状态协调"]
end
| 维度 | 单机模式 | 集群模式 |
|---|---|---|
| 元数据存储 | 本地文件(H2) | 注册中心(ZooKeeper / ETCD) |
| 实例间感知 | 无法感知 | 实时同步 |
| 配置变更 | 仅当前实例生效 | 全集群即时生效 |
| 适用场景 | 本地开发测试 | 生产环境 |
6.2 集群模式配置
JDBC 端集群模式配置:
mode:
type: Cluster # 集群模式
repository:
type: ZooKeeper # 注册中心类型:ZooKeeper / ETCD
props:
namespace: governance_ds # 命名空间(隔离不同集群)
server-lists: localhost:2181 # ZooKeeper 地址(多个逗号分隔)
retryIntervalMilliseconds: 500 # 重试间隔
timeToLiveSeconds: 60 # 节点存活时间
maxRetries: 3 # 最大重试次数
operationTimeoutMilliseconds: 500 # 操作超时时间
Proxy 端集群模式配置(server.yaml):
mode:
type: Cluster
repository:
type: ZooKeeper
props:
namespace: governance_proxy
server-lists: zk1:2181,zk2:2181,zk3:2181
retryIntervalMilliseconds: 500
timeToLiveSeconds: 60
maxRetries: 3
operationTimeoutMilliseconds: 500
6.3 混合部署架构
生产环境推荐 JDBC + Proxy 混合部署,各取所长:
graph TB
subgraph 应用层
Java["Java 应用<br/>(OLTP)"] --> JDBC["ShardingSphere-JDBC"]
Other["异构语言应用<br/>(OLAP)"] --> Proxy["ShardingSphere-Proxy"]
DBA["DBA / 运维"] --> Proxy
end
JDBC --> ZK["注册中心<br/>ZooKeeper"]
Proxy --> ZK
ZK -->|"共享元数据<br/>统一配置"| Config["分片规则<br/>读写分离规则<br/>加密规则"]
JDBC --> M0["MySQL 主库 0"]
JDBC --> M1["MySQL 主库 1"]
JDBC --> S0["MySQL 从库 0"]
JDBC --> S1["MySQL 从库 1"]
Proxy --> M0
Proxy --> M1
Proxy --> S0
Proxy --> S1
七、DistSQL:声明式管理
DistSQL(Distributed SQL)是 ShardingSphere 扩展的 SQL 方言,允许通过 SQL 语句动态管理分片规则、数据源等,无需重启服务。
通过 Proxy 连接后即可使用:
-- 查看所有数据源
SHOW SCHEMA RESOURCES FROM sharding_db;
-- 动态添加数据源
ADD RESOURCE ds_2 (
HOST="127.0.0.1", PORT=3306, DB="shardingdb2",
USER="root", PASSWORD="your_password"
);
-- 创建分片规则
CREATE SHARDING TABLE RULE t_order (
DATANODES("ds_${0..2}.t_order_${0..1}"),
DATABASE_STRATEGY(TYPE="standard", SHARDING_COLUMN=user_id, SHARDING_ALGORITHM(TYPE(NAME=inline, PROPERTIES("algorithm-expression"="ds_${user_id % 3}")))),
TABLE_STRATEGY(TYPE="standard", SHARDING_COLUMN=order_id, SHARDING_ALGORITHM(TYPE(NAME=inline, PROPERTIES("algorithm-expression"="t_order_${order_id % 2}"))))
);
-- 查看分片规则
SHOW SHARDING TABLE RULES;
-- 查看真实 SQL 路由
PREVIEW SELECT * FROM t_order WHERE user_id = 1;
DistSQL 让 DBA 能够在不修改配置文件、不重启服务的情况下动态调整分片规则,非常适合生产环境运维。
八、常见问题与最佳实践
8.1 分片键选择
分片键的选择直接影响系统性能,遵循以下原则:
- 高频查询字段优先:选择 WHERE 条件中最常出现的字段,避免全路由扫描
- 数据分布均匀:避免数据倾斜,如按用户 ID 取模通常比按时间分片更均匀
- 避免频繁更新:分片键一旦确定不宜变更,更新分片键值会导致数据迁移
- 考虑关联查询:主子表使用相同分片键配置为绑定表,减少跨库 JOIN
8.2 跨库查询优化
graph TD
Q["查询请求"] --> R{"是否包含分片键?"}
R -->|是| S1["精确路由<br/>单库单表执行"]
R -->|否| S2["全路由广播<br/>所有分表执行并归并"]
S2 --> S3{"是否使用绑定表?"}
S3 -->|是| S4["绑定表 JOIN 走同路由<br/>避免笛卡尔积"]
S3 -->|否| S5["跨库 JOIN<br/>使用联邦查询或应用层组装"]
避免全路由扫描的建议:
- 尽量在查询条件中带上分片键
- 使用绑定表优化主子表关联查询
- 复杂跨库分析查询使用联邦查询(SQL Federation)
- 合理使用广播表减少跨库 JOIN
8.3 常见问题排查
问题 1:启动报错 “Cannot find sharding.yaml”
确认配置文件位于 src/main/resources/ 目录下,且 application.yml 中的路径正确:
url: jdbc:shardingsphere:classpath:sharding.yaml
问题 2:SQL 路由到全部分表
检查 SQL 是否包含分片键条件。如果没有分片键,ShardingSphere 会广播到所有分表执行。开启 sql-show: true 查看实际路由情况。
问题 3:分片算法表达式报错
INLINE 算法使用 Groovy 表达式,注意以下规则:
# 正确:取模运算
algorithm-expression: ds_${user_id % 2}
# 正确:字符串哈希取模
algorithm-expression: ds_${Math.abs(id.hashCode() % 2)}
# 错误:MOD 算法不支持表达式,应使用 INLINE
# shardingAlgorithms:
# xxx:
# type: MOD # MOD 只接受 sharding-count 参数
# props:
# algorithm-expression: ... # 这行会报错
问题 4:分布式事务不生效
确认已引入对应的事务管理器依赖,且配置文件中正确指定了事务类型。XA 事务需要数据库支持 XA 协议(MySQL 的 InnoDB 引擎支持)。
问题 5:Proxy 连接报权限错误
检查 server.yaml 中的认证配置,确认用户名密码正确,且权限策略允许当前操作:
rules:
- !AUTHORITY
users:
- root@%:root # @% 表示允许任意 IP 连接
provider:
type: ALL_PERMITTED # 生产环境应使用 SCHEMA_PRIVILEGES_PERMITTED 细化权限
8.4 生产环境检查清单
| 检查项 | 说明 |
|---|---|
| 运行模式 | 生产环境必须使用 Cluster 模式 + ZooKeeper/ETCD |
| 连接池参数 | 根据业务并发量调整 maxPoolSize、minPoolSize |
| 事务类型 | 根据一致性要求选择 XA 或 BASE |
| 权限策略 | Proxy 端使用 SCHEMA_PRIVILEGES_PERMITTED 而非 ALL_PERMITTED |
| 日志级别 | 生产环境关闭 sql-show,避免日志膨胀 |
| 监控告警 | 接入 Prometheus + Grafana 监控连接数、SQL 执行时间 |
| 数据备份 | 定期备份注册中心元数据和物理数据库 |
| 版本管理 | 通过 BOM 统一管理 ShardingSphere 组件版本 |
九、版本升级与生态
从旧版本升级到 5.5.3
5.5.3 相比 5.x 早期版本有以下不兼容变更,升级时需注意:
- 分片规则持久化移除
default_strategies前缀 - Proxy 移除 SQL 格式化及日志规则(logging rule)功能
- Proxy 移除配置项
system-log-level,SQL 日志 topic 调整为org.apache.shardingsphere.sql - 建议通过 BOM 统一管理依赖版本,避免传递依赖冲突
相关资源
- 官方文档:https://shardingsphere.apache.org/document/5.5.3/cn/overview/
- 下载页面:https://shardingsphere.apache.org/document/5.5.3/cn/downloads/
- GitHub 仓库:https://github.com/apache/shardingsphere
- 更新日志:https://github.com/apache/shardingsphere/blob/master/RELEASE-NOTES.md
- Cloud 子项目:https://github.com/apache/shardingsphere-on-cloud
本教程覆盖了 ShardingSphere 5.5.3 的核心概念、两种部署形态的快速集成、分片/读写分离/事务/加密/脱敏等功能配置,以及生产部署的最佳实践。建议先在本地用单机模式跑通 ShardingSphere-JDBC 的分库分表示例,再逐步尝试读写分离和 Proxy 部署,最后过渡到集群模式的生产架构。