主题
Sharding-Sphere
Apache ShardingSphere 是一套开源的分布式数据库中间件解决方案,提供了数据分片、读写分离、分布式事务、数据加密等功能。它支持多种数据库(MySQL、PostgreSQL、SQL Server、Oracle 等),可以透明化地实现数据库的横向扩展。
核心特性
- 数据分片:支持分库分表,支持多种分片策略
- 读写分离:支持一主多从的读写分离
- 分布式事务:支持 XA、Seata、BASE 等分布式事务
- 数据加密:支持数据加密存储和查询
- 分布式治理:支持配置中心、注册中心
- 多数据库支持:支持 MySQL、PostgreSQL、Oracle 等
核心概念
- 逻辑表:水平拆分的数据库(表)的同一类表的总称
- 真实表:在分片的数据库中真实存在的物理表
- 数据节点:数据分片的最小单元,由数据源名称和数据表组成
- 分片键:用于分片的数据库字段
- 分片算法:用于分片的算法
Spring Boot 集成
添加依赖
在 pom.xml 中添加 ShardingSphere 依赖:
xml
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.4.0</version>
</dependency>分库分表配置
在 application.yml 中配置分库分表:
yaml
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/db0
username: root
password: root
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db1
username: root
password: root
rules:
sharding:
tables:
# 配置逻辑表
t_order:
# 真实数据节点
actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
# 分库策略
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: database-inline
# 分表策略
table-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: table-inline
# 分片算法配置
sharding-algorithms:
database-inline:
type: INLINE
props:
algorithm-expression: ds$->{user_id % 2}
table-inline:
type: INLINE
props:
algorithm-expression: t_order_$->{order_id % 2}
# 显示 SQL
props:
sql-show: true分片策略
标准分片策略
使用单个分片键进行分片:
yaml
table-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: table-inline复合分片策略
使用多个分片键进行分片:
yaml
table-strategy:
complex:
sharding-columns: user_id,order_id
sharding-algorithm-name: complex-inline行表达式分片策略
使用 Groovy 表达式进行分片:
yaml
sharding-algorithms:
table-inline:
type: INLINE
props:
algorithm-expression: t_order_$->{order_id % 4}自定义分片策略
实现 StandardShardingAlgorithm 接口:
java
public class CustomShardingAlgorithm implements StandardShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
Long orderId = shardingValue.getValue();
// 自定义分片逻辑
String tableName = "t_order_" + (orderId % 4);
return tableName;
}
@Override
public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
// 范围查询的分片逻辑
return availableTargetNames;
}
@Override
public void init() {
// 初始化
}
@Override
public String getType() {
return "CUSTOM";
}
}读写分离
配置读写分离
yaml
spring:
shardingsphere:
datasource:
names: master,slave0,slave1
master:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/master
username: root
password: root
slave0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/slave0
username: root
password: root
slave1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/slave1
username: root
password: root
rules:
readwrite-splitting:
data-sources:
readwrite-ds:
type: Static
props:
write-data-source-name: master
read-data-source-names: slave0,slave1
load-balancer-name: round-robin
load-balancers:
round-robin:
type: ROUND_ROBIN强制路由到主库
在某些场景下,需要强制从主库读取数据:
java
@Autowired
private HintManager hintManager;
public void forceMaster() {
hintManager.setWriteRouteOnly();
// 执行查询,会路由到主库
// ...
hintManager.close();
}分布式事务
XA 事务
使用 XA 协议实现分布式事务:
yaml
spring:
shardingsphere:
rules:
transaction:
default-type: XA
provider-type: AtomikosSeata 事务
集成 Seata 实现分布式事务:
yaml
spring:
shardingsphere:
rules:
transaction:
default-type: BASE
provider-type: Seata在代码中使用:
java
@Transactional
public void createOrder(Order order) {
// 跨库操作会自动使用分布式事务
orderMapper.insert(order);
orderItemMapper.insert(orderItem);
}数据加密
配置数据加密
yaml
spring:
shardingsphere:
rules:
encrypt:
encryptors:
aes-encryptor:
type: AES
props:
aes-key-value: 123456
tables:
t_user:
columns:
phone:
cipher-column: phone_cipher
encryptor-name: aes-encryptor使用加密字段
java
// 插入时自动加密
userMapper.insert(user); // phone 字段会自动加密存储到 phone_cipher
// 查询时自动解密
User user = userMapper.selectById(1); // phone_cipher 会自动解密到 phone绑定表
绑定表是指分片规则一致的主表和子表,可以避免跨库关联查询:
yaml
spring:
shardingsphere:
rules:
sharding:
binding-tables:
- t_order,t_order_item
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
table-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: table-inline
t_order_item:
actual-data-nodes: ds$->{0..1}.t_order_item_$->{0..1}
table-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: table-inline广播表
广播表是指所有分片数据源中都存在的表,表结构和数据在每个数据库中完全一致:
yaml
spring:
shardingsphere:
rules:
sharding:
broadcast-tables:
- t_config分片算法类型
取模分片
yaml
sharding-algorithms:
mod-algorithm:
type: MOD
props:
sharding-count: 4哈希分片
yaml
sharding-algorithms:
hash-algorithm:
type: HASH_MOD
props:
sharding-count: 4范围分片
yaml
sharding-algorithms:
range-algorithm:
type: CLASS_BASED
props:
strategy: STANDARD
algorithmClassName: com.example.RangeShardingAlgorithm时间分片
yaml
sharding-algorithms:
time-algorithm:
type: INTERVAL
props:
datetime-pattern: yyyy-MM-dd HH:mm:ss
datetime-lower: 2020-01-01 00:00:00
datetime-upper: 2024-12-31 23:59:59
sharding-suffix-pattern: yyyyMM
datetime-interval-amount: 1
datetime-interval-unit: MONTHS使用示例
实体类
java
@Data
@TableName("t_order")
public class Order {
private Long orderId;
private Long userId;
private String orderNo;
private BigDecimal amount;
private Date createTime;
}Mapper
java
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
@Select("SELECT * FROM t_order WHERE user_id = #{userId}")
List<Order> selectByUserId(@Param("userId") Long userId);
}Service
java
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
public void createOrder(Order order) {
orderMapper.insert(order);
}
public List<Order> getOrdersByUserId(Long userId) {
return orderMapper.selectByUserId(userId);
}
}最佳实践
- 合理选择分片键:选择数据分布均匀的字段作为分片键
- 避免跨库事务:尽量在同一个分片内完成事务
- 使用绑定表:避免跨库关联查询
- 合理设置分片数量:避免分片过多导致管理复杂
- 监控和优化:监控 SQL 执行情况,优化慢查询
- 数据迁移:制定完善的数据迁移方案
常见问题
跨库查询
- 使用绑定表避免跨库关联
- 使用应用层聚合数据
- 使用全局表(广播表)
分布式事务
- 根据业务场景选择合适的分布式事务方案
- XA 事务保证强一致性,但性能较低
- BASE 事务保证最终一致性,性能较高
数据迁移
- 使用 ShardingSphere 的数据迁移工具
- 制定完善的迁移方案和回滚方案
- 在业务低峰期进行迁移
ShardingSphere 作为强大的分库分表中间件,可以帮助企业轻松实现数据库的横向扩展,提升系统的性能和可扩展性。