【分库分表】基于mysql+shardingSphere的分库分表技术

小灰灰 2024-04-25 20:21 164阅读 0赞

目录

1.什么是分库分表

2.分片方法

3.测试数据

4.shardingSphere

4.1.介绍

4.2.sharding jdbc

4.3.sharding proxy

4.4.两者之间的对比

5.留个尾巴


1.什么是分库分表

分库分表是一种场景解决方案,它的出现是为了解决一些场景问题的,哪些场景喃?

  • 单表过大的话,读请求进来,查数据需要的时间会过长
  • 读请求过多,单节点IO压力太大,IO压力太大会造成什么?可能会造成IO阻塞,造成响应速度变慢。

分库分表是指的两种维度,一种维度是分库,另一种维度是分表。分的话有两种分法,一种是水平分,另一种是垂直分。

水平分是指将数据分为多段,一个服务器节点上存放一段,读写的时候走自己要的那一段所在服务器上。一段也叫一个分片(sharding)

88f2a044136c423d8d8d86b3dc2af63a.png

垂直分是指将一个库或者一个表从一个整体拆成多个部分,不同服务器上存储一部分:

d8c1aefa1b0045208e2e8455ec1d22ef.png

2.分片方法

其实总的来说分库都还好,垂直分库对应着服务拆成微服务做到资源隔离各玩儿各的,问题都还不大,而且一般不会出现水平分库,因为库里面数据多的也就某一些表,我们面对更多的是水平分表。水平分表首先要面对的就是如何分片?

分片方法有如下几种:

  • hash分片法
  • range分片法

hash分片法:

主键对服务器数量取余。

5fe2455d707f4877bd807058e84789a2.png

这种方式在扩容后数据需要重新散列一遍,重新散列一遍花时间吗?当然花时间,但是不散列又不行,为什么喃?举个例,原来id=12的数据散列到了0表,扩容后不迁移的话按照规则id=12的表会散列到4表,这就会导致id=12这条数据在查找的时候找不到:

7eb6096a6d6844078611efedaaccbabf.png

当然hash算法可以用一致性hash算法来优化,但其数据迁移肯定是无法规避的,且一致性hash算法本身也存在无法规避的缺点。博主之前有一篇一致性hash算法的文章,可移步:

一致性hash算法_一直hash算法-CSDN博客

range分片法:

按照编号顺序均匀的分片,好处是扩容不用散列,但是新数据往往是使用频率更高的数据,会导致压力不均匀,而且现在一般唯一ID为了安全性都是无序的,比如采用UUID做主键的时候,所以range分片法的场景适用也很有限。

f49e6670bf2e4b4c80f98a2747b09ffc.png

3.测试数据

用一张订单表来做测试数据,根据主键来分库分表:

  1. create table order_(
  2. id varchar(100) primary key,
  3. productName VARCHAR(100),
  4. productId VARCHAR(100),
  5. createTime datetime,
  6. statue INT
  7. )ENGINE=INNODB;

准备了两个库,db01和db02都有这张订单表:

f316390f4aa64a75af95a936ea51e0ea.png

依赖版本:

千万注意版本的对齐!

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-web</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-test</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.springframework.boot</groupId>
  12. <artifactId>spring-boot-starter-actuator</artifactId>
  13. </dependency>
  14. <!--prometheus -->
  15. <dependency>
  16. <groupId>io.micrometer</groupId>
  17. <artifactId>micrometer-registry-prometheus</artifactId>
  18. </dependency>
  19. <!-- MySQL驱动 -->
  20. <dependency>
  21. <groupId>mysql</groupId>
  22. <artifactId>mysql-connector-java</artifactId>
  23. <version>8.0.29</version>
  24. </dependency>
  25. <!-- MyBatis Plus Starter -->
  26. <dependency>
  27. <groupId>com.baomidou</groupId>
  28. <artifactId>mybatis-plus-boot-starter</artifactId>
  29. <version>3.5.1</version>
  30. </dependency>
  31. <!--sharding-jdbc-->
  32. <dependency>
  33. <groupId>org.apache.shardingsphere</groupId>
  34. <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
  35. <version>4.1.1</version>
  36. </dependency>
  37. <!-- Alibaba Druid 数据源 -->
  38. <dependency>
  39. <groupId>com.alibaba</groupId>
  40. <artifactId>druid</artifactId>
  41. <version>1.2.8</version>
  42. </dependency>
  43. <dependency>
  44. <groupId>org.projectlombok</groupId>
  45. <artifactId>lombok</artifactId>
  46. <version>1.18.24</version>
  47. </dependency>
  48. </dependencies>
  49. <dependencyManagement>
  50. <dependencies>
  51. <dependency>
  52. <groupId>org.springframework.boot</groupId>
  53. <artifactId>spring-boot-dependencies</artifactId>
  54. <version>2.6.3</version>
  55. <type>pom</type>
  56. <scope>import</scope>
  57. </dependency>
  58. </dependencies>
  59. </dependencyManagement>

4.shardingSphere

4.1.介绍

分片方法说起来容易,要自己去实现一个全过程的分片分表还是很繁琐的,需要手动实现多数据源,然后实现散列算法来控制读写请求映射到哪一台服务器,升级一点的功能还包括要与服务器进行心跳通信,获取服务器的信息等等。所以说还是直接用”轮子”吧。

Apache ShardingSphere 是一个开源的分布式数据库中间件解决方案,它由阿里巴巴集团开源,目前是 Apache 软件基金会旗下的顶级项目。ShardingSphere 通过提供一组与数据库交互的标准化接口(如JDBC驱动或代理服务),对上层应用隐藏了复杂的分布式数据库处理逻辑,为开发者提供了易用且功能强大的分库分表、读写分离、数据治理、弹性伸缩等功能。

ShardingSphere分为三部分:Sharding-JDBC、Sharding-Proxy、Sharding-Sidecar。

4.2.sharding jdbc

其中Sharding-JDBC,其会托管JDBC,然后支持实现分库分表、读写分离。分库分表和读写分离都是通过配置实现的,配置好数据源,然后配置好分库规则即可。当然读写分离的前提是数据库已经配置成了读写分离的模式。以下是配置示例:

  1. spring:
  2. application:
  3. name: testDemo
  4. shardingsphere:
  5. datasource:
  6. names: ds0,ds1
  7. ds0:
  8. driver-class-name: com.mysql.cj.jdbc.Driver
  9. type: com.alibaba.druid.pool.DruidDataSource
  10. url: jdbc:mysql://localhost:3306/db01?serverTimezone=UTC
  11. username: root
  12. password: admin
  13. ds1:
  14. driver-class-name: com.mysql.cj.jdbc.Driver
  15. type: com.alibaba.druid.pool.DruidDataSource
  16. url: jdbc:mysql://localhost:3306/db02?serverTimezone=UTC
  17. username: root
  18. password: admin
  19. sharding:
  20. default-database-strategy:
  21. inline:
  22. sharding-column: order_id
  23. algorithm-expression: ds$->{order_id % 2}
  24. tables:
  25. t_order:
  26. actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
  27. table-strategy:
  28. inline:
  29. sharding-column: order_id
  30. algorithm-expression: t_order_$->{order_id % 2}
  31. #读写分离
  32. master-slave-rules:
  33. ms_ds:
  34. master-data-source-name: ds0
  35. slave-data-source-names: ds1
  36. load-balance-algorithm-type: ROUND_ROBIN #负载均衡算法
  37. props:
  38. sql.show: true #是否打印sql

上述YAML配置已经使用了inline表达式实现了基于order_id字段的分库和分表规则。当然还提供了接口,对于自定义分库、分表规则,可以通过实现ShardingSphere提供的接口来自定义算法类,并在配置中引用这些类。

  1. public class CustomDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Integer> {
  2. @Override
  3. public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Integer> shardingValue) {
  4. // 根据order_id和其他可能的业务逻辑计算数据库名称
  5. int orderId = shardingValue.getValue();
  6. return "ds" + (orderId % 2); // 这里仅作为示例,实际请根据业务需求编写
  7. }
  8. }
  9. spring:
  10. application:
  11. name: testDemo
  12. shardingsphere:
  13. # ... 数据源配置 ...
  14. sharding:
  15. default-database-strategy:
  16. precise:
  17. sharding-column: order_id
  18. algorithm-class-name: com.example.CustomDatabaseShardingAlgorithm
  19. tables:
  20. t_order:
  21. actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
  22. table-strategy:
  23. precise:
  24. sharding-column: order_id
  25. # 同样可以为表级别分片指定自定义算法类
  26. algorithm-class-name: com.example.CustomTableShardingAlgorithm
  27. # ... 读写分离配置 ...
  28. props:
  29. sql.show: true

同样的,如果需要自定义分表规则,也需要创建一个实现相应接口(如PreciseShardingAlgorithm)的类,并在table-strategy部分通过algorithm-class-name属性引用它。以上示例中的CustomTableShardingAlgorithm即是一个假设存在的自定义分表策略类。请确保实际应用中已正确创建并配置此类。

4.3.sharding proxy

sharding proxy是一个中间件,也能实现分库分表和读写分离。不同于sharding jdbc需要侵入代码中对JDBC进行一个托管,sharding

proxy是无侵入式的,一个独立的组件。

sharding proxy需要先下载,然后解压、配置。

配置示例:

配置数据库的信息

dd7b5811771a4769ac0f2cc5402525cd.png

然后需要导入mysql的驱动:

6f11c6f056ce437293045474dd438a71.png

配置分库分表:

这里要注意了databaseName指向的数据库是一个总库,应用都会往这个库里面进行数据读写,然后由sharding proxy来向我们配置的不同数据源里进行分库分表。给出一个配置文件,大家感受一下,该配置文件基于Apache ShardingSphere 5.x版本的语法编写。不同版本可能配置项存在不同哈。

  1. # config-sharding.yaml
  2. schemaName: testDemo # 指定逻辑库名称
  3. rules:
  4. - !SHARDING
  5. dataSources:
  6. ds0:
  7. url: jdbc:mysql://localhost:3306/db01?serverTimezone=UTC
  8. username: root
  9. password: admin
  10. connectionTimeoutMilliseconds: 30000
  11. idleTimeoutMilliseconds: 60000
  12. maxLifetimeMilliseconds: 1800000
  13. type: com.alibaba.druid.pool.DruidDataSource
  14. ds1:
  15. url: jdbc:mysql://localhost:3306/db02?serverTimezone=UTC
  16. username: root
  17. password: admin
  18. # 其他连接池属性...
  19. shardingRule:
  20. tables:
  21. t_order:
  22. actualDataNodes: ds$->{0..1}.t_order_$->{0..1}
  23. databaseStrategy:
  24. inline:
  25. shardingColumn: order_id
  26. algorithmExpression: ds$->{order_id % 2}
  27. tableStrategy:
  28. inline:
  29. shardingColumn: order_id
  30. algorithmExpression: t_order_$->{order_id % 2}
  31. masterSlaveRules:
  32. ms_ds:
  33. masterDataSourceName: ds0
  34. slaveDataSourceNames: [ds1]
  35. loadBalanceAlgorithmType: ROUND_ROBIN
  36. props:
  37. sql.show: true

4.4.两者之间的对比

sharding jdbc是侵入了应用,托管了JDBC,对代码有侵入性。

sharding proxy是对数据库下手,其并没用侵入数据库,也没用上数据库的bin log,而是去监听数据库的端口从而来拦截下sql。

但是proxy明显可以看到是中心化的,都在向一个点来写数据,是会有性能瓶颈的。

5.留个尾巴

不管是水平拆还是垂直拆,分库分表后一定会存在两个核心问题:

  • 不好join,需要在程序层面进行join
  • 分布式事务

sharding是如何解决第一个问题的喃?首先sharding会各个节点上进行全表扫描,用类似笛卡尔积的办法聚合成最终的结果。

至于第二个问题,留在后文,我们将深入探究一下sharding生态圈是如何实现分布式事务的。除此之外还有一些尾巴要留在后文继续展开,包括:

  • sharding jdbc是如何托管JDBC的
  • sharding proxy是否存在中心化架构带来的性能问题?有没有办法规避?

发表评论

表情:
评论列表 (有 0 条评论,164人围观)

还没有评论,来说两句吧...

相关阅读

    相关 分库技术简述

    今天和大家聊聊分库分表技术,大家面试的时候肯定都有这样的经历,面试官动不动就问分库分表、高并发、虚拟机、分布式事务等等这些高大上的技术。所以我们还是有必要要了解一下的。 分表

    相关 分库

    分库分表 为什么分库分表 在高并发和海量数据的场景下,通过使用分库分表的手段,能够解决单机或者单库单表的性能瓶颈和压力,突破IO、连接数、硬件资源的瓶颈。当然,投入

    相关 分库

    一. 数据切分 关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库、优

    相关 分库

    一、常见面试题 1、为什么分表分库? 2、分表分库中间件有哪些?分别有什么特点? 3、垂直拆分还是水平拆分?有什么区别? 二、问题分析 1、由于用户数量增长,