1. 为什么需要分库分表
当业务数据量达到千万级甚至亿级时,单机数据库很快就会遇到性能瓶颈。我经历过一个电商项目,订单表数据量突破5000万后,简单的查询都要耗时数秒,更别提高峰期并发写入时的锁竞争问题了。这时候就需要引入分库分表方案,而ShardingSphere正是Java生态中最成熟的选择之一。
ShardingSphere是一套开源的分布式数据库中间件解决方案,由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar组成。其中Sharding-JDBC最适合与Spring Boot集成,它工作在客户端层面,以jar包形式提供服务,不需要额外部署中间件。
2. 环境准备与基础配置
2.1 依赖引入
首先在pom.xml中添加必要依赖:
xml复制<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
注意:ShardingSphere 5.x版本开始使用新的命名空间,与4.x配置不兼容。如果是从旧版本升级需要特别注意。
2.2 数据源配置
在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: 123456
ds1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db1
username: root
password: 123456
这里配置了两个物理数据库db0和db1,分别对应ds0和ds1数据源。实际生产环境建议将不同数据源部署在不同物理机器上。
3. 分片策略设计与实现
3.1 水平分表配置
假设我们有一个订单表t_order,需要按照订单ID的哈希值分片到两个数据库中,每个库中再按创建时间月份分表:
yaml复制spring:
shardingsphere:
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{202301..202312}
database-strategy:
standard:
sharding-column: order_id
precise-algorithm-class-name: com.example.config.OrderDatabaseShardingAlgorithm
table-strategy:
standard:
sharding-column: create_time
precise-algorithm-class-name: com.example.config.OrderTableShardingAlgorithm
3.2 自定义分片算法实现
数据库分片算法示例:
java复制public class OrderDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
long orderId = shardingValue.getValue();
// 按订单ID哈希取模决定库
int dbIndex = (int) (orderId % availableTargetNames.size());
return "ds" + dbIndex;
}
}
表分片算法示例:
java复制public class OrderTableShardingAlgorithm implements PreciseShardingAlgorithm<Date> {
@Override
public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> shardingValue) {
Date createTime = shardingValue.getValue();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
String month = sdf.format(createTime);
return "t_order_" + month;
}
}
实际项目中建议将分片算法配置为Spring Bean,避免每次重新实例化。
4. 高级特性与最佳实践
4.1 分布式主键生成
ShardingSphere内置了雪花算法生成分布式ID:
yaml复制spring:
shardingsphere:
rules:
sharding:
key-generators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 123
tables:
t_order:
key-generate-strategy:
column: order_id
key-generator-name: snowflake
4.2 读写分离配置
可以结合主从复制实现读写分离:
yaml复制spring:
shardingsphere:
rules:
replica-query:
data-sources:
pr_ds:
primary-data-source-name: ds0
replica-data-source-names: ds0_slave,ds1_slave
load-balancer-name: round_robin
load-balancers:
round_robin:
type: ROUND_ROBIN
4.3 性能优化建议
-
分片键选择:选择高基数列作为分片键,避免数据倾斜。订单ID、用户ID等都是不错的选择。
-
绑定表:有关联查询的表使用相同的分片规则:
yaml复制t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{202301..202312}
t_order_item:
actual-data-nodes: ds$->{0..1}.t_order_item_$->{202301..202312}
binding-tables: t_order
- 广播表:小数据量字典表配置为广播表,在所有库中同时存在:
yaml复制t_province:
actual-data-nodes: ds$->{0..1}.t_province
broadcast: true
5. 常见问题排查
5.1 分片键修改问题
一旦数据插入后,分片键值不可修改,否则会导致数据"丢失"(实际是找不到正确分片)。解决方案:
- 业务上禁止更新分片键
- 如需修改,先删除原记录再插入新记录
5.2 跨库关联查询
尽量避免跨库JOIN,解决方案:
- 使用绑定表确保关联表数据在同一分片
- 在应用层做数据聚合
- 考虑使用ShardingSphere的联邦查询功能
5.3 分布式事务
对于需要跨分片的事务操作:
- 简单场景可使用本地事务+最终一致性
- 复杂场景集成Seata等分布式事务框架:
yaml复制spring:
shardingsphere:
rules:
sharding:
default-database-strategy:
none:
default-table-strategy:
none:
props:
sql-show: true
allow-hint-disable: true
# Seata配置
transaction:
type: BASE
seata:
enable: true
application-id: your_app_id
tx-service-group: your_tx_group
6. 监控与运维
6.1 启用SQL日志
开发环境可以开启SQL日志方便调试:
yaml复制spring:
shardingsphere:
props:
sql-show: true
6.2 使用Prometheus监控
配置metrics暴露端点:
yaml复制spring:
shardingsphere:
props:
metrics:
enabled: true
name: prometheus
host: 0.0.0.0
port: 9090
然后在Prometheus配置中抓取该端点即可监控ShardingSphere运行状态。
6.3 数据迁移工具
当现有分片规则需要调整时,可以使用ShardingSphere-Scaling进行在线数据迁移:
- 编写迁移配置YAML文件
- 执行启动命令:
bash复制sh bin/start.sh --config=conf/config.yaml
迁移过程中业务可以继续读写,工具会自动同步增量数据。