Springboot3 shardingsphere 5.2.1 分库分表实践
明月别枝惊鹊,清风半夜鸣蝉。
1 前言
在互联网和大数据时代,单一数据库难以满足高并发和海量数据的存储需求。Apache ShardingSphere
作为一个强大的分布式数据库中间件,提供了高效的分库分表功能,以应对日益复杂的存储挑战。本文将以 为基础添加分库分表业务,本文以 ShardingSphere 5.2.1
版本为实践案例,深入分析其使用中的注意事项。
2 项目准备
在前文中已经讲述了项目搭建的过程,对于 ShardingSphere
的引入,只需要在 pom
项目中引入 ShardingSphere
的依赖即可。以下是 maven
的依赖配置,这已经是最新的:
-- 依赖排除了 quartz 的引用,在 sharding-sphere-starter 中集成了很多模块,对于不需要的可以进行排除,这一点和 nacos-discovery 类似。
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
<version>5.2.1</version>
<exclusions>
<exclusion>
<artifactId>quartz</artifactId>
<groupId>org.quartz-scheduler</groupId>
</exclusion>
</exclusions>
</dependency>
3 分库分表策略和算法
3.1 分库分表策略
在新版本中分库分表策略包含有标准分片策略、复合分片策略、Hin分片策略、不分片策略。分片策略就是分片键+分片算法。具体如下图所示,详见YamlShardingStrategyConfiguration
。
分片策略 | 使用条件 | 操作符 |
---|---|---|
标准分片策略 | 使用单一分片键的,支持精确分片。需要指定分片字段shardingColumn 和分片算法名shardingAlgorithmName | =、in 、between and、 >、 < 、>=、<= |
复合分片策略 | 适用于多个分片键的场景,分片字段shardingColumn 使用逗号间隔 | 支持条件和标准分片相同 |
强制分片策略 | 无需配置分片键,由外部指定分库分表信息。使用场景:1 分片字段不再收据库结构而在外部业务,2 强制在指定数据库进行数据操作。 | - |
不分片策略 | 对逻辑表的所有操作都会在全库表进行路由操作。 | - |
3.2 分库分表算法
ShardingSphere 5.2.1
中新增了许多分片字段,按照类型划分可以分为自动分片算法,标准分片算法,复合分片算法以及 Hint 分片算法,基本上覆盖到了大多数的业务场景。 这里需要说明一下,分库和分表的算法都是一样的,想要知道所有的分片算法,可以看 StandardShardingAlgorithm
的实现类即可。
分片算法 | 配置说明 | 算法说明 |
---|---|---|
自动分片-MOD | 需要指定 sharding-count ,即分片数量 | 取模是一种内置的简单分算法,表达式为 (分片键或者数据库实例) % sharding-count |
自动分片-HASHMOD | 同样需要指定分片数量 sharding-count | 和简单取模算法类似,不过换成了 hash 值取模,如果hash 取模为负数,会取其绝对值 |
自动分片-VOLUME_RANGE | 需要指定分片键取值的上下限(range-lower, range-upper) ,以及每个分片的容量 sharding-volume , 超过容量边界后会报错 | 基于分片容量的范围分片算法,将数据按照容量均分到数据库表中 |
自动分片-BOUNDARY_RANGE | 根据边界值进行分片,和容量算法不同,需要指定范围的分界 sharding-ranges=1000,2000,30000,40000 ,按照数据边界可以分为5个数据库表。 | 根据边界值将数据分别放在对应的分表中。 |
自动分片-AUTO_INTERVAL | 自动时间分片算法,和基于容量分片算法类似,不过这里采用的分片键为时间。需要指定时间的上下限,(datetime-lower,datetime-upper) , 对应的时间戳格式为 yyyy-MM-dd HH:mm:ss ,以及对应的分片容纳时间,sharding-seconds , 单位为秒。 | 按照时间的方式将数据路由到不同的数据库表中。 |
行表达式-INLINE | 适用于比较简单的分片场景,需要指定分片表达式 algorithm-expression ,以及是否支持范围查询 allow-range-query-with-inline-sharding ,默认为 false | 基于行表达式的分片算法,使用 groovy语言,能够直观的看出分片的计算逻辑,只能支持 = 和 in 的 sql 操作 |
行表达式-INTERVAL | 基于时间的分片,上面的时间分片算法都是以 _n 为后缀,这里可以使用表后缀为_yyyyMMdd 的格式。指定分片键的时间格式 datetime-pattern,默认为yyyy-MM-dd HH:mm:ss ,分片值的取值范围(datetime-lower,datetime-upper) ,需要和分片键的格式一致,分片表的后缀格式 sharding-suffix-pattern 一般为 yyyyMM、yyyyMMdd 格式,分片表的单位间隔 datetime-interval-unit 取值为 MONTHS、DAYS ,需要和 datetime-interval-amount 配合使用。 | 基于时间分表算法,可以直观的看出数据存储的时间范围。 |
复合分片-COMPLEX_INLINE | 适用于多个分片键场景,多个分片键需要使用逗号间隔, 这里比 INLINE多了一个分片列 sharding-columns | 和行表达式的原理类似,也是需要使用 groovy 语言指定分片算法。 |
HINT分片-HINT_INLINE | 强制路由分片算法,需要指定算法的表达式 algorithm-expression , 其中的分片值需要在代码中通过 HintApi 进行指定。 | 是一种根据业务需要计算分片路由的算法,在特殊的业务场景下使用。 |
此外,还有基于散列算法 COSID(一款高性能的分布式ID生成器)
,其核心思想是通过散列算法和分片键值进行处理,可以保证数据存放的均匀性,避免数据倾斜和个别节点负载高的问题。有以下三种分片算法 COSID_MOD
、 COSID_INTERVAL
、COSID_INTERVAL_SNOWFLAKE
,所需要的配置只是多添加了一个 真实表的前缀 logic-name-prefix
。
4 分库分表配置
对于分库分表的配置,ShardingSphere
提供了两种 java api
��� yml
两种配置,这里采用的是配置文件的方式,由于分库分表的配置项很多,这里采用了 properties
的配置,个人觉得比 yml
容易理解。
在开始配置之前,需要先配置数据库连接信息,如下图所示:
现在有一个 tb_order 表,分片键为 user_id , 需要进行分库分表, 例如 tb_order_2024_01
,需要按照年份分表,每个年份分为5个表,同时需要分布在两个数据库中。首先需要设置分库分表的后缀范围:
# 设置分库分表后缀范围
spring.shardingsphere.rules.sharding.tables.tb_order.actual-data-nodes=db${0..1}.tb_order_$->{2020..2030}_${(0..4).collect{t ->t.toString().padLeft(2,'0')}}
分库策略比较简单,按照 user_id
取模运算,配置如下所示:
# 分库的策略配置
spring.shardingsphere.rules.sharding.tables.tb_order.database-strategy.standard.sharding-column=user_id
spring.shardingsphere.rules.sharding.tables.tb_order.database-strategy.standard.sharding-algorithm-name=database_inline
# 采用行表达式的方式进行分库
spring.shardingsphere.rules.sharding.sharding-algorithms.database_inline.type=INLINE
spring.shardingsphere.rules.sharding.sharding-algorithms.database_inline.props.algorithm-expression=db${user_id % 2}
分表的策略比较复杂,这里采用了自定义的分表策略,在配置中如下所示:
# 配置分表分片键
spring.shardingsphere.rules.sharding.tables.tb_order.table-strategy.standard.sharding-column=user_id
spring.shardingsphere.rules.sharding.tables.tb_order.table-strategy.standard.sharding-algorithm-name=table_inline
# 这里采用 snowflake 生成 tb_order 的主键
spring.shardingsphere.rules.sharding.tables.tb_order.key-generate-strategy.column=id
spring.shardingsphere.rules.sharding.tables.tb_order.key-generate-strategy.key-generator-name=alg_snowflake
spring.shardingsphere.rules.sharding.key-generators.alg_snowflake.type=SNOWFLAKE
spring.shardingsphere.rules.sharding.key-generators.alg_snowflake.props.worker-id=12
# 分表策略,这里采用的是自定义分表策略,需要继承 StandardShardingAlgorithm
spring.shardingsphere.rules.sharding.sharding-algorithms.table_inline.type=USER_SHARDING_STRATEGY
spring.shardingsphere.rules.sharding.sharding-algorithms.table_inline.props.number=5
在自定义分片算法时,需要在 resources 中配置其分片策略,同时需要采用编程的方式实现接口的方法,进行分片操作。
这里如果不区分年份的话,可以采用行表达式的方式来实现分表,如下所示:
# 行表达式的分表算法
spring.shardingsphere.rules.sharding.sharding-algorithms.table_inline.type=INLINE
# 由于采用的是 groovy 语言,可以很灵活的实现,user_id 对5取模后+1,得到的是 1-5 的数,
# 这里采用了格式化两位展示,十位数补零,如果有两位数的表,这样的表名看起来比较整齐。
spring.shardingsphere.rules.sharding.sharding-algorithms.table_inline.props.algorithm-expression=tb_order_${String.valueOf(user_id % 5 + 1).padLeft(2,'0')}
除了正常的分库分表之外,还可以设置不分库分表、以及广播表、或者是分库不分表(只需要设置分库规则即可)。
配置实际操作表和广播表
# 配置实际表
spring.shardingsphere.rules.sharding.tables.tb_account.actual-data-nodes=db1.tb_account
# 配置广播表
spring.shardingsphere.rules.sharding.broadcast-tables=tb_config
5 注意事项
- 1 分片键选择
选择合适的分片键非常重要。分片键应为业务中频繁查询和过滤的字段,如订单系统中的 user_id
或 order_id
。合理的分片键选择可以显著提升查询性能。
-
- 扩展性
在设计分库分表时,应考虑未来的扩展性。可以预留一些数据节点和表,以便在数据量增长时平滑扩展。例如,初始时可以设置更多的实际数据节点,并通过动态调整分片算法来实现扩展。
-
- 数据迁移
对于已有的大量数据,需要精心规划数据迁移策略。可以采用数据迁移工具或编写迁移脚本,将数据平滑地迁移到新的分片结构中,确保数据迁移过程中的一致性和完整性。
-
- 分布式事务
分库分表后,事务处理变得更加复杂。可以使用 ShardingSphere
提供的分布式事务管理器,如 XA
事务、BASE
事务,或者引入第三方分布式事务解决方案,如 Seata
,以确保事务的一致性和可靠性。
-
- 性能监控
在分库分表环境中,性能监控尤为重要。通过监控系统的性能指标,及时发现和优化分片策略和数据库配置,保证系统的高可用性和稳定性。可以使用 Prometheus
、Grafana
等工具进行性能监控和告警。
-
- 数据均衡
确保数据在各个分片中的均衡分布,避免某些分片数据量过大而影响性能。可以定期进行数据重分布,保持数据的均衡性。例如,可以通过调整分片算法或者重新分配数据节点来实现数据均衡。
-
- SQL 限制
由于分库分表的限制,部分 SQL
特性可能不被支持,如跨库 Join
和复杂子查询。在使用 ShardingSphere
时,需注意规避这些限制,优化 SQL
语句。例如,可以通过分批查询和应用层 Join
的方式来实现跨库查询。
6 总结
ShardingSphere 5.2.1
版本作为一个功能强大的分布式数据库中间件,为解决海量数据和高并发请求提供了高效的分库分表解决方案。在实际应用中,通过合理配置和使用 ShardingSphere
,可以显著提升系统的扩展性和性能。通过关注分片键选择、数据迁移、分布式事务和性能监控等关键环节,可以确保系统的稳定性和一致性,为企业应用保驾护航。本文中所涉及的代码已经上传至 gitee
, 欢迎交流学习。项目地址 fortunecloud。
转载自:https://juejin.cn/post/7393314542095237130