1. 为什么需要分库分表?
当业务数据量达到千万级甚至亿级时,单库单表的性能瓶颈就会逐渐显现。我经历过一个电商系统,订单表数据量突破5000万后,简单的查询都要花费2-3秒,更不用说复杂的报表统计了。这时候就需要考虑分库分表方案。
传统解决方案通常采用应用层硬编码实现数据路由,这种方式存在几个明显问题:
- 业务代码与数据路由逻辑高度耦合
- 不同业务需要重复开发相似的分片逻辑
- 扩容时需要修改代码并迁移数据
- 缺乏统一的事务管理机制
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. ShardingSphere核心架构解析
ShardingSphere采用三层架构设计,完美解决了上述痛点:
2.1 接入层(ShardingSphere-Proxy)
提供透明化的数据库代理服务,支持MySQL/PostgreSQL协议。我们项目中使用的是5.1.2版本,通过Docker快速部署:
bash复制docker run -d \
-p 3307:3307 \
-e PORT=3307 \
apache/shardingsphere-proxy:5.1.2
2.2 内核层(ShardingSphere-JDBC)
轻量级的Java框架,在JDBC层进行增强。核心配置示例:
yaml复制spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/db0
username: root
password: 123456
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..15}
table-strategy:
standard:
sharding-column: order_id
precise-algorithm-class-name: com.demo.MyPreciseShardingAlgorithm
2.3 功能层
提供分布式事务、数据加密、影子库等企业级功能。特别值得一提的是分布式事务,支持XA和Seata两种模式:
java复制// 开启XA事务
@ShardingSphereTransactionType(TransactionType.XA)
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
// 业务逻辑
}
3. 分片策略实战指南
3.1 分片算法选型
根据业务特点选择合适的分片算法是关键。我们用户表采用哈希取模分片,订单表则使用按时间范围分片:
java复制public class TimeRangeShardingAlgorithm implements StandardShardingAlgorithm<Date> {
@Override
public String doSharding(Collection<String> availableTargetNames,
PreciseShardingValue<Date> shardingValue) {
// 按季度分表
LocalDate date = shardingValue.getValue().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate();
int quarter = (date.getMonthValue() - 1) / 3 + 1;
return "t_order_" + date.getYear() + "q" + quarter;
}
}
3.2 分片键设计原则
- 选择高基数列(如用户ID、订单ID)
- 避免热点数据集中(不要用性别作为分片键)
- 考虑业务查询模式(常用查询条件应包含分片键)
重要提示:分片键一旦确定后修改成本极高,建议前期充分论证
4. 性能优化实战经验
4.1 连接池配置
使用HikariCP连接池时,建议配置:
yaml复制minimum-idle: 5
maximum-pool-size: 20
idle-timeout: 60000
max-lifetime: 1800000
connection-timeout: 30000
4.2 分布式ID生成
推荐使用Snowflake算法,避免使用数据库自增ID。我们在生产环境采用改进版:
java复制public class CustomSnowflake {
private static final long SEQUENCE_BITS = 12;
private static final long WORKER_ID_BITS = 5;
private static final long DATACENTER_ID_BITS = 5;
// 时间戳左移22位
// 数据中心ID左移17位
// 工作机器ID左移12位
// 序列号不位移
}
5. 常见问题排查手册
5.1 全表扫描问题
现象:SQL执行缓慢,日志显示路由到所有分片
解决方案:
- 检查SQL是否包含分片键
- 配置sharding.default-database-strategy
- 使用Hint强制路由
5.2 分布式事务超时
现象:XA事务频繁回滚
优化方案:
- 调整超时时间:spring.shardingsphere.props.xa-transaction-manager-timeout=60
- 减少单个事务操作的数据量
- 考虑改用BASE事务模式
6. 监控与运维实践
6.1 监控指标配置
通过Prometheus采集关键指标:
yaml复制metrics:
enabled: true
name: histogram_request_latency
help: "Histogram of request latency"
labels: ["success"]
6.2 数据迁移方案
使用ShardingSphere-Scaling进行在线迁移:
bash复制bin/start.sh \
--config=conf/config.yaml \
--rule=conf/rule.yaml \
--dataSource=conf/datasource.yaml
在实际项目中,我们通过分阶段迁移策略,将2TB的订单数据从单库迁移到16个分片,整个过程业务无感知。关键是要做好数据校验和灰度发布,我们开发了专门的数据比对工具来确保一致性。
