ShardingSphere分库分表实战与优化指南

发布时间:2026/8/9 11:25:29
ShardingSphere分库分表实战与优化指南 1. 为什么需要分库分表在业务系统发展初期我们通常采用单一数据库来存储所有数据。但随着业务规模扩大单库单表会面临几个明显的瓶颈问题数据量瓶颈当单表数据超过500万行时即使有索引查询性能也会显著下降。我曾处理过一个电商订单表当数据量达到800万时简单分页查询需要3秒以上响应时间。连接数瓶颈MySQL默认最大连接数是1515.7版本在高并发场景下很容易耗尽。去年双十一期间某支付系统就因连接数不足导致服务不可用。硬件瓶颈单机服务器的CPU、内存、磁盘IO都有物理上限。垂直升级硬件成本呈指数增长一台高端数据库服务器的价格可能是普通服务器的10倍。运维风险所有数据集中在一个库一旦出现故障就是全局性影响。去年我们遇到过主库磁盘损坏导致全站服务中断6小时的事故。提示分库分表不是银弹它会带来分布式事务、跨库JOIN等新问题。建议在单表数据预计超过500万前就开始规划。2. ShardingSphere核心架构解析2.1 三大核心模块对比ShardingSphere包含三个独立又相互关联的产品模块名称定位适用场景最新版本ShardingSphere-JDBC轻量级Java框架需要嵌入业务代码的Java应用5.5.3ShardingSphere-Proxy透明化数据库代理多语言环境或不能改代码的遗留系统5.5.3ShardingSphere-SidecarKubernetes云原生方案服务网格环境5.5.3在实际项目中我们团队最常用的是ShardingSphere-JDBC。它通过在应用层重写SQL语句实现分片性能损耗小于5%远低于Proxy的20%网络开销。2.2 分片核心流程当执行SELECT * FROM orders WHERE user_id 1001时ShardingSphere的处理流程SQL解析使用ANTLR将SQL解析为抽象语法树(AST)查询优化根据分片规则重写查询条件路由计算通过分片键user_id1001确定目标分片SQL改写将原始SQL改为SELECT * FROM orders_1 WHERE user_id 1001结果归并如果查询涉及多个分片合并结果集3. SpringBoot集成实战3.1 版本兼容性踩坑最近在升级项目时遇到一个典型问题springboot: 2.7.18 shardingsphere-jdbc-core-spring-boot-starter: 5.2.1启动时报错Failed to determine a suitable driver class。这是因为5.2.1版本对SpringBoot 2.7.x支持不完善。解决方案有两种降级SpringBoot到2.6.x升级ShardingSphere到5.5.3推荐我们最终采用方案二修改后配置implementation org.apache.shardingsphere:shardingsphere-jdbc-core-spring-boot-starter:5.5.33.2 完整配置示例以下是电商订单分库分表的完整配置基于5.5.3版本spring: shardingsphere: datasource: names: ds0,ds1 ds0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://db0:3306/order_db?useSSLfalse username: root password: 123456 ds1: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://db1:3306/order_db?useSSLfalse username: root password: 123456 rules: sharding: tables: t_order: actual-data-nodes: ds$-{0..1}.t_order_$-{0..15} database-strategy: standard: sharding-column: user_id precise-algorithm-class-name: com.example.OrderDatabaseShardingAlgorithm table-strategy: standard: sharding-column: order_id precise-algorithm-class-name: com.example.OrderTableShardingAlgorithm关键配置说明actual-data-nodes定义物理表分布这里表示2个库每个库16张表database-strategy按user_id分库table-strategy按order_id分表4. 分片算法设计与优化4.1 自定义分片算法实现我们采用用户ID后两位模2分库订单ID哈希模16分表public class OrderDatabaseShardingAlgorithm implements StandardShardingAlgorithmLong { Override public String doSharding(CollectionString availableTargetNames, PreciseShardingValueLong shardingValue) { long userId shardingValue.getValue(); int suffix (int) (userId % 100); return ds (suffix % 2); } } public class OrderTableShardingAlgorithm implements StandardShardingAlgorithmLong { Override public String doSharding(CollectionString availableTargetNames, PreciseShardingValueLong shardingValue) { long orderId shardingValue.getValue(); return t_order_ (orderId % 16); } }4.2 分片键选择原则好的分片键应该满足离散度高如用户ID比性别更适合业务相关性经常作为查询条件避免热点不要用单调递增的ID我们曾用时间戳做分片键结果导致所有新数据都写入最后一个分片。后来改为用户ID订单ID组合分片才解决。5. 生产环境问题排查5.1 分布式ID冲突问题使用数据库自增ID会导致不同分表产生相同ID。我们采用美团Leaf方案解决// 在实体类中使用 Id GeneratedValue(generator leaf) GenericGenerator(name leaf, strategy com.meituan.leaf.spring.LeafSnowflakeStrategy) private Long orderId;5.2 跨库查询性能优化对于需要跨分片的查询如管理员后台我们采用以下方案并行查询配置max.connections.size.per.query5结果缓存对不常变的数据使用Redis缓存异构索引在Elasticsearch建立只读索引spring: shardingsphere: props: max.connections.size.per.query: 5 sql.show: true6. 监控与运维实践6.1 关键监控指标我们在Prometheus中监控这些关键指标分片查询耗时分布数据源连接池状态SQL错误类型统计分布式事务成功率Grafana监控看板示例查询sum(rate(shardingsphere_statement_latency_milliseconds_sum[1m])) by (sql_type) / sum(rate(shardingsphere_statement_latency_milliseconds_count[1m])) by (sql_type)6.2 数据迁移方案当需要增加分片数量时我们使用ShardingSphere-Scaling工具curl -X POST \ http://localhost:8888/scaling/job/start \ -H Content-Type: application/json \ -d { ruleConfig: { sourceDatasource: ds_old, targetDatasource: ds_new }, jobConfiguration: { concurrency: 4 } }迁移过程中会自动保持数据一致性业务几乎无感知。去年我们用这套方案在高峰期完成了从8分片到16分片的扩容。