经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 编程经验 » 查看文章
分库分表如何管理不同实例中几万张分片表?
来源:cnblogs  作者:程序员小富  时间:2024/2/26 15:04:54  对本文有异议

大家好,我是小富~

ShardingSphere实现分库分表,如何管理分布在不同数据库实例中的成千上万张分片表?

上边的问题是之前有个小伙伴看了我的分库分表的文章,私下咨询我的,看到他的提问我第一感觉就是这老铁没用过ShardingSphere,因为这个问题在ShardingSphere中已经有了很好的解决方案,接下来看看怎么实现。

本文案例代码GitHub地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-autocreate-table

系列往期

往期系列文章(我佛系更新,无下限拖更):

(一)好好的系统,为什么要分库分表?

(二)分库分表的 21 条法则,hold 住!

(三)2 种方式快速实现分库分表,轻松拿捏!

ShardingSphere学习路线

本文是《ShardingSphere5.x分库分表原理与实战》系列的第四篇文章,在进行分库分表设计时,确认好了数据节点数量和分片策略以后,接下来要做的就是管理大量的分片表。实际实施过程中可能存在上百个分片数据库实例,每个实例中都可能有成千上万个分片表,如果仅依靠人力来完成这些任务显然是不现实的。所以,想要快速且自动化管理这些分片表,使用工具是十分必要滴。

前言

ShardingSphere框架成员中的Shardingsphere-jdbcShardingsphere-proxy都提供了自动化管理分片表的功能auto-tables,可以统一维护大量的分片表,避免了手动编写脚本和维护分片表的繁琐工作,极大程度减少分库分表的开发和维护成本,提升效率和可靠性。

这里咱们先使用Shardingsphere-jdbc来实际操作一下,Shardingsphere-proxy方式后续会有单独的文章详细讲解,就不在这里展开了。

准备工作

假设我们要对t_order表进行分库分表,首先我们要做的就是确定好分片方案,这里使用两个数据库实例db0db1,每个实例中t_order表分成1000张分片表t_order_1 ~ t_order_1000order_id字段作为分片键,分片算法使用取模算法order_id % n,分布式主键生成策略采用snowflake

t_order逻辑表的表结构如下:

  1. CREATE TABLE `t_order` (
  2. `order_id` BIGINT ( 20 ) NOT NULL COMMENT "订单表分布式主健ID",
  3. `order_number` VARCHAR ( 255 ) NOT NULL COMMENT "订单号",
  4. `customer_id` BIGINT ( 20 ) NOT NULL COMMENT "用户ID",
  5. `order_date` date NOT NULL COMMENT "下单时间",
  6. `total_amount` DECIMAL ( 10, 2 ) NOT NULL COMMENT "订单金额",
  7. PRIMARY KEY ( `order_id` ) USING BTREE
  8. );

有了这些基础信息,可以先来进行t_order表的分片配置了,不考虑其他因素,这里先Run起来!

分片规则配置

设定好分片规则,接着编写逻辑表t_order的分片规则的配置,我分别使用yml配置Java编码两种方式做了实现。要注意的是两种方式不要并存,不然启动会报错

yml配置方式

使用yml配置相对简单易用比较直观,适合对分库分表要求不太复杂的场景,完整配置如下:

  1. spring:
  2. shardingsphere:
  3. datasource:
  4. # 数据源名称,多数据源以逗号分隔 ,放在第一个的数据源为未配置分片规则表的默认数据源
  5. names: db0 , db1
  6. # 名称与上边 names 保持一致
  7. db0:
  8. ....
  9. db1:
  10. ....
  11. # 具体规则配置
  12. rules:
  13. sharding:
  14. # 分片算法定义
  15. sharding-algorithms:
  16. # 自定义分片算法名称
  17. t_order_database_algorithms:
  18. # 分片算法类型
  19. type: INLINE
  20. # 自定义参数
  21. props:
  22. algorithm-expression: db$->{order_id % 2}
  23. t_order_table_algorithms:
  24. type: INLINE
  25. props:
  26. algorithm-expression: t_order_$->{order_id % 1000}
  27. t_order_mod:
  28. type: MOD
  29. props:
  30. # 指定分片数量
  31. sharding-count: 1000
  32. # 分布式序列算法配置
  33. key-generators:
  34. t_order_snowflake:
  35. type: SNOWFLAKE
  36. # 分布式序列算法属性配置
  37. props:
  38. worker-id: 1
  39. tables:
  40. # 逻辑表名称
  41. t_order:
  42. # 数据节点:数据库.分片表
  43. actual-data-nodes: db$->{0..1}.t_order_$->{1..1000}
  44. # 分库策略
  45. database-strategy:
  46. standard:
  47. # 分片列名称
  48. sharding-column: order_id
  49. # 分片算法名称
  50. sharding-algorithm-name: t_order_database_algorithms
  51. # 分表策略
  52. table-strategy:
  53. standard:
  54. # 分片列名称
  55. sharding-column: order_id
  56. # 分片算法名称
  57. sharding-algorithm-name: t_order_table_algorithms
  58. # 主键生成策略
  59. keyGenerateStrategy:
  60. column: order_id
  61. keyGeneratorName: t_order_snowflake
  62. # 属性配置
  63. props:
  64. # 展示修改以后的sql语句
  65. sql-show: true

Java编码方式

使用Java编码方式更加灵活和可扩展,可以根据业务定制分片规则,适合对分库分表有特殊需求或需要动态调整的场景。

  1. /**
  2. * 公众号:程序员小富
  3. */
  4. @Configuration
  5. public class ShardingConfiguration {
  6. /**
  7. * 配置分片数据源
  8. * 公众号:程序员小富
  9. */
  10. @Bean
  11. public DataSource getShardingDataSource() throws SQLException {
  12. Map<String, DataSource> dataSourceMap = new HashMap<>();
  13. dataSourceMap.put("db0", dataSource0());
  14. dataSourceMap.put("db1", dataSource1());
  15. // 分片rules规则配置
  16. ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
  17. // 分片算法
  18. shardingRuleConfig.setShardingAlgorithms(getShardingAlgorithms());
  19. // 配置 t_order 表分片规则
  20. ShardingTableRuleConfiguration orderTableRuleConfig = new ShardingTableRuleConfiguration("t_order", "db${0..1}.t_order_${1..1000}");
  21. orderTableRuleConfig.setTableShardingStrategy(new StandardShardingStrategyConfiguration("order_id", "t_order_table_algorithms"));
  22. orderTableRuleConfig.setDatabaseShardingStrategy(new StandardShardingStrategyConfiguration("order_id", "t_order_database_algorithms"));
  23. shardingRuleConfig.getTables().add(orderTableRuleConfig);
  24. // 是否在控制台输出解析改造后真实执行的 SQL
  25. Properties properties = new Properties();
  26. properties.setProperty("sql-show", "true");
  27. // 创建 ShardingSphere 数据源
  28. return ShardingSphereDataSourceFactory.createDataSource(dataSourceMap, Collections.singleton(shardingRuleConfig), properties);
  29. }
  30. /**
  31. * 配置数据源1
  32. * 公众号:程序员小富
  33. */
  34. public DataSource dataSource0() {
  35. HikariDataSource dataSource = new HikariDataSource();
  36. dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
  37. dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/db0?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true");
  38. dataSource.setUsername("root");
  39. dataSource.setPassword("123456");
  40. return dataSource;
  41. }
  42. /**
  43. * 配置数据源2
  44. * 公众号:程序员小富
  45. */
  46. public DataSource dataSource1() {
  47. HikariDataSource dataSource = new HikariDataSource();
  48. dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
  49. dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true");
  50. dataSource.setUsername("root");
  51. dataSource.setPassword("123456");
  52. return dataSource;
  53. }
  54. /**
  55. * 配置分片算法
  56. * 公众号:程序员小富
  57. */
  58. private Map<String, AlgorithmConfiguration> getShardingAlgorithms() {
  59. Map<String, AlgorithmConfiguration> shardingAlgorithms = new LinkedHashMap<>();
  60. // 自定义分库算法
  61. Properties databaseAlgorithms = new Properties();
  62. databaseAlgorithms.setProperty("algorithm-expression", "db$->{order_id % 2}");
  63. shardingAlgorithms.put("t_order_database_algorithms", new AlgorithmConfiguration("INLINE", databaseAlgorithms));
  64. // 自定义分表算法
  65. Properties tableAlgorithms = new Properties();
  66. tableAlgorithms.setProperty("algorithm-expression", "db$->{order_id % 1000}");
  67. shardingAlgorithms.put("t_order_table_algorithms", new AlgorithmConfiguration("INLINE", tableAlgorithms));
  68. return shardingAlgorithms;
  69. }
  70. }

上面我们在应用中编写好了分片规则,现在就差在数据库实例中创建分片表了,手动创建和管理1000张分片表确实是一个又脏又累的活,反正我是不会干的!

管理分片表

其实,ShardingSphere内已经为我们提供了管理分片表的能力。

当一张逻辑表t_order被配置了分片规则,那么接下来对逻辑表的各种DDL操作(例如创建表修改表结构等),命令和数据会根据分片规则,执行和存储到每个分片数据库和分片库中的相应分片表中,以此保持整个分片环境的一致性。

不过,使用Shardingsphere-jdbc管理分片表的过程中,是需要我们手动编写对逻辑表的DDL操作的代码。我们来跑几个单元测试用例来观察实际的执行效果,直接使用jdbcTemplate执行创建逻辑表t_order的SQL。

  1. /**
  2. * @author 公众号:程序员小富
  3. * 自动创建分片表
  4. * @date 2023/12/31 17:25
  5. */
  6. @SpringBootTest
  7. class AutoCreateTablesTests {
  8. @Resource
  9. private JdbcTemplate jdbcTemplate;
  10. /**
  11. * 执行创建逻辑表的SQL,会根据AutoTables的配置自动在对应的数据源内创建分片表
  12. * @author 公众号:程序员小富
  13. */
  14. @Test
  15. public void autoCreateOrderTableTest() {
  16. jdbcTemplate.execute("CREATE TABLE `t_order` (\n" +
  17. " `order_id` bigint(20) NOT NULL,\n" +
  18. " `order_number` varchar(255) NOT NULL,\n" +
  19. " `customer_id` bigint(20) NOT NULL,\n" +
  20. " `order_date` date NOT NULL,\n" +
  21. " `total_amount` decimal(10,2) NOT NULL,\n" +
  22. " PRIMARY KEY (`order_id`) USING BTREE\n" +
  23. ");");
  24. }
  25. }

根据之前配置的分片规则,将会在两个数据库实例 db0db1 中,分别生成1000张命名为t_order_1t_order_1000的分片表,看到两个数据库均成功创建了1000张分片表。

在次执行更新t_order表SQL,将字段order_number长度从 varchar(255)扩展到 varchar(500),执行SQL看下效果。

  1. /**
  2. * @author 公众号:程序员小富
  3. * 自动创建分片表
  4. * @date 2023/12/31 17:25
  5. */
  6. @SpringBootTest
  7. class AutoCreateTablesTests {
  8. @Resource
  9. private JdbcTemplate jdbcTemplate;
  10. @Test
  11. public void autoModifyOrderTableTest() {
  12. jdbcTemplate.execute("ALTER TABLE t_order MODIFY COLUMN order_number varchar(500);");
  13. }
  14. }

通过查看两个分片库,我们成功地将所有分片表的order_number字段长度更改为了varchar(500),在控制台日志中,可以看到它是通过在每个分片库内依次执行了1000次命令实现的。

Shardingsphere-jdbc实现分库分表时,可以采用这种默认的方式来管理分片表。但要注意的是,由于涉及到不同的数据库实例,如果不使用第三方的分布式事务管理工具(例如Seata等),执行过程是无法保证事务一致性的。

自定义管理分片表

上边为逻辑表配置分片规则,应用程序内执行对逻辑表的DDL操作,就可以很轻松的管理分片表。

自定义

不过,默认的分片管理还是有局限性的,我们在设计分片规则时往往会根据不同的业务维度来划分,例如按天、月、按季度生成分片表并分布到不同数据源中等。这样就需要一些自定义的规则来实现。

ShardingSphere 5.X版本后推出了一种新的管理分片配置方式:AutoTable。设置了AutoTable的逻辑表,将交由ShardingSphere自动管理分片,用户只需要指定分片数量和使用的数据库实例,无需再关心表的具体分布,配置格式如下:

  1. spring:
  2. shardingsphere:
  3. # 数据源配置
  4. datasource:
  5. ......
  6. # 具体规则配置
  7. rules:
  8. sharding:
  9. # 逻辑表分片规则
  10. tables:
  11. # 逻辑表名称
  12. t_order:
  13. .....
  14. # 自动分片表规则配置
  15. auto-tables:
  16. t_order: # 逻辑表名称
  17. actual-data-sources: db$->{0..1}
  18. sharding-strategy: # 切分策略
  19. standard: # 用于单分片键的标准分片场景
  20. sharding-column: order_id # 分片列名称
  21. sharding-algorithm-name: t_order_mod # 自动分片算法名称

ShardingSphere-Jdbc中配置使用auto-tables主要两个参数,actual-data-sources指定数据源分布,由于是管理分片表所以只需数据源信息即可;sharding-strategy指具体采用何种算法来进行分片。

对逻辑表的DDL操作,系统会首先检查是否配置了AutoTable,如果已配置,则优先采用配置的规则;若未配置,则将使用默认的逻辑表分片规则。

AutoTable支持ShardingSphere内置的全部自动分片算法,所谓自动分片算法就是根据actualDataSources设置的数据源信息,使用对应内置算法自行解析处理。

  • MOD:取模分片算法
  • HASH_MOD:哈希取模分片算法
  • VOLUME_RANGE:基于分片容量的范围分片算法
  • BOUNDARY_RANGE:基于分片边界的范围分片算法
  • AUTO_INTERVAL:自动时间段分片算法

AutoTable使用

举个例子,我们使用内置MOD取模算法作为AutoTable的分片算法,同样是db0db1两个实例中各创建1000张分片表。那么当对逻辑表的DDL操作时,ShardingSphere会依据分片表编号t_order_0~t_order_1999 % 数据库实例数取模来确认DDL命令路由到哪个实例中执行。

  1. spring:
  2. shardingsphere:
  3. # 数据源配置
  4. datasource:
  5. .....
  6. # 具体规则配置
  7. rules:
  8. sharding:
  9. # 自动分片表规则配置
  10. auto-tables:
  11. t_order:
  12. actual-data-sources: db$->{0..1}
  13. sharding-strategy:
  14. standard:
  15. sharding-column: order_date
  16. sharding-algorithm-name: t_order_mod
  17. # 分片算法定义
  18. sharding-algorithms:
  19. t_order_mod:
  20. type: MOD
  21. props:
  22. # 指定分片数量
  23. sharding-count: 2000

还是执行刚才创建表的单元测试,会发现db0db1两个实例中已经各自创建了1000张分片表,但你会发现1000张表已经不再是按照顺序创建的了。

上边使用的是内置自动分片算法,它对于我们来说是黑盒,提供它方便我们拿来即用。不过,如果想要做到更细粒度的管理分片表,最好的办法就是自定义分片算法,后续章节会介绍所有内置分片算法和自定义分片算法的使用

总结

在使用ShardingSphere实现分库分表的时候,要摒弃先建表、再配规则的传统思维,要先确定规则在建表,管理表是一件很简单的事,我们只要告诉ShardingSphere分片数量和分布规则,剩下的就让框架来处理就好了。

本文案例代码GitHub地址:https://github.com/chengxy-nds/Springboot-Notebook/tree/master/shardingsphere101/shardingsphere-autocreate-table

我是小富~ 下期见

原文链接:https://www.cnblogs.com/chengxy-nds/p/18034214

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号