数据库-分库分表

时间:2024-10-07 11:46:09

什么是分库分表

分库分表是一种数据库优化策略

目的:为了解决由于单一的库表数据量过大而导致数据库性能降低的问题

分库:将原来独立的数据库拆分成若干数据库组成

分表:将原来的大表(存储近千万数据的表)拆分成若干个小表

什么时候考虑分库分表

​ 注意:当我们使用读写分离、索引、缓存后,数据库的压力还是很大的时候,这就需要将数据库进行拆分(迫不得已,最后最后的办法)。

  1. 单表出现的瓶颈:单表数据量过大,导致读写性能较慢。 关于 MySQL 单库和单表的数据量限制,和不同的服务器配置,以及不同结构的数据存储有关,并没有一个确切的数字。这里参考阿里巴巴的《Java 开发手册》中数据库部分的建表规约:单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。

  2. 单库出现的瓶颈:CPU压力过大,内存不足,磁盘空间不足,网络带宽不足,导致读写性能较慢

分库分表的实现方式

​ 分库分表包括分库和分表两个部分,在生产中通常包括:垂直分库、水平分库、垂直分表、水平分表四种方式。

1.垂直分表

概念:按照字段访问频次,将一张表的字段拆分到多张表当中。

拆分后表的记录行数不变拆分的表之间一般是一对一的关系每张表仅存储其中一部分字段

2.垂直分库

概念:按照业务将表进行分类,分布到不同的数据库上面。

核心理念:专库专用

注意:它需要解决跨库带来的所有复杂问题(例如:事务一致性问题)。

<img src="C:\Users\txt\AppData\Roaming\Typora\typora-user-images\image-20241006100449332.png" alt="image-20241006100449332" style="zoom: 46%;" />

3.水平分表

概念:整张表在数据结构不变的情况下,将大表按一定规则拆分成多个小表

算法说明:如果商品ID为偶数,将此操作映射至商品信息1表;如果商品ID为奇数,将操作映射至商品信息2表。此操作要访问表名称的表达式为商品信息[商品ID%2 + 1];

4.水平分库

概念:将表水平切分后 按某个字段的某种规则分到不同的数据库,使得每个库具有相同的表,表中的数据不相同,水平分库一般是伴随水平分表。

场景:假如当前有8w店铺,每个店铺平均150个不同规格的商品,那商品数量得往1200w+上预估,并且商品库属于访问非常频繁的资源,单台服务器已经无法支撑。此时该如何优化?​ 目前情况是那怕再次垂直分库也无法解决数据瓶颈问题。我们可以尝试水平分库,将商品ID为奇数的和商品ID为偶数的商品信息分别放在两个不同库中;说明:总之,水平分库后,各个库保存的表结构是一致的,但是表中内容不一样;

最佳实践:

一般来说,在系统设计阶段就应该根据业务耦合松紧来确定垂直分库,垂直分表方案。当然在数据量及访问压力不是特别大的情况,首先考虑缓存、读写分离、索引技术等方案。若数据量极大,且持续增长,再考虑水平分库水平分表方案。

总之,基于开发和维护成本比考虑,非必须,不要对数据库做分库分表处理!

分库分表带来的问题(了解)

单个数据库的时候MySQL操作很简单,但是当进行分库分表之后数据库被拆分的非常细,这个时候如何操作这些表就是要面临的问题,就需要引入sharding-jdbc,来解决分库分表操作的问题,sharding-jdbc不是进行分库分表的,分库分表是已经提前分好的,sharding-jdbc是解决了如何方便的去操作这些数据库表。

分库分表(Sharding)是一种常见的数据库扩展方案,用于提高系统的性能和可扩展性。然而,分库分表也会带来一些复杂性和挑战。ShardingSphere(原名 Sharding-JDBC,现在是 Apache *项目)是一个强大的开源框架,旨在帮助开发者解决这些挑战。下面我将详细讨论分库分表带来的问题以及 ShardingSphere 能否解决这些问题。

  1. 分布式事务

  2. 问题:在分库分表的环境中,一个业务操作可能涉及多个数据库或表,这会导致分布式事务的问题。

  3. 解决方案ShardingSphere 支持多种分布式事务解决方案,如 XA、Seata 等,可以有效地处理跨库事务。

  4. 全局唯一 ID 生成

  5. 问题:在分库分表的情况下,需要生成全局唯一的主键 ID。

  6. 解决方案ShardingSphere 提供了多种 ID 生成策略,如 Snowflake、UUID 等,可以确保生成的 ID 在全局范围内唯一。

  7. 数据迁移和扩容

  8. 问题:随着业务的发展,可能需要对现有的分片规则进行调整或增加新的分片。

  9. 解决方案ShardingSphere 提供了灵活的数据迁移和扩容工具,支持在线数据迁移和重新分片。

  10. 查询路由

  11. 问题:查询请求需要被正确地路由到相应的分片上。

  12. 解决方案ShardingSphere 内置了强大的 SQL 解析和路由引擎,能够自动解析 SQL 并将其路由到正确的分片。

  13. 聚合查询

  14. 问题:跨分片的聚合查询(如 GROUP BY, ORDER BY)会变得复杂。

  15. 解决方案ShardingSphere 支持跨分片的聚合查询,并通过内存计算或中间结果集合并来实现高效的聚合。

  16. 读写分离

  17. 问题:为了进一步提高性能,可能需要实现读写分离。

  18. 解决方案ShardingSphere 支持读写分离,可以将读操作路由到从库,写操作路由到主库。

  19. 配置管理

  20. 问题:分库分表的配置较为复杂,需要管理和维护。

  21. 解决方案ShardingSphere 提供了灵活的配置方式,支持 YAML、Spring Boot 配置文件等,方便管理和维护。

  22. 数据一致性

  23. 问题:在分库分表的情况下,数据的一致性难以保证。

  24. 解决方案ShardingSphere 提供了多种一致性保证机制,如最终一致性、强一致性等,可以根据业务需求选择合适的方案。

  25. 监控和运维

  26. 问题:分库分表后的系统监控和运维变得更加复杂。

  27. 解决方案ShardingSphere 提供了丰富的监控和日志功能,支持与 Prometheus、Grafana 等监控系统集成,便于运维。

ShardingSphere 是一个非常强大的框架,能够解决分库分表带来的大部分问题。它提供了全面的解决方案,包括分布式事务、全局唯一 ID 生成、数据迁移和扩容、查询路由、聚合查询、读写分离、配置管理、监控和运维等。虽然 ShardingSphere 可以解决很多问题,但在实际应用中,还需要根据具体的业务需求和场景进行适当的配置和调优。此外,对于一些非常复杂的业务逻辑和特定需求,可能仍需要额外的定制化开发。

Sharding-JDBC入门

1、ShardingSphere生态简介

​ Apache ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(计划中)这3款相互独立的产品组成,既能够独立部署,又支持混合部署配合使用的产品组成。

功能特性:它们均提供标准化的数据水平扩展分布式事务分布式治理等功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

文档地址:https://shardingsphere.apache.org/document/legacy/4.x/document/cn/overview

本教程主要介绍:Sharding-JDBC

​ Sharding-jdbc是ShardingSphere的其中一个模块,定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架

<dependency>            <groupId>org.apache.shardingsphere</groupId>            <artifactId>sharding-jdbc-spring-boot-starter</artifactId>            <version>4.0.0-RC1</version></dependency>

Java

  • 适用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。

  • 基于任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。

  • 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer和PostgreSQL。

Sharding-JDBC的核心功能为数据分片读写分离,通过Sharding-JDBC,应用可以透明的使用jdbc访问已经分库分表、读写分离的多个数据源,而不用关心数据源的数量以及数据如何分布。

数据分片:把表和数据库进行拆分读写分离:把数据库分成主从两个数据库,主数据库负责写,从数据库负责读

2、sharding-jdbc相关名词解释

参考官网-核心概念

  • 逻辑表(LogicTable):(面向开发,实际上是不存在的表)进行水平拆分的时候同一类型(逻辑、数据结构相同)的表的总称。

  • 真实表(ActualTable):(真实存在的表,真实操作的表)在分片的数据库中真实存在的物理表。

  • 数据节点(DataNode):(描述的是哪个数据源下的哪张表,相当与地理位置的定位)数据分片的最小单元。由数据源名称和数据表组成,例:order_db.t_order_1, order_db.t_order_2,order_db.t_order_3 说白了,具体到指定库下的指定表就是一个数据节点;

  • 动态表(DynamicTable):(属于真实表,随某种规则动态产生)逻辑表和物理表不一定需要在配置规则中静态配置。如,按照日期分片的场景,物理表的名称随着时间的推移会产生变化(股票流水)。

  • 广播表(公共表):(数据量较小,变动少,而且属于高频联合查询的依赖表)指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表:对数据库结构的详细描述、参数表。

  • 绑定表(BindingTable):多表之间存在关系,尽量关联的数据放到一个库中,避免跨库查询(让相同字段都参与到分库的规则,就会落到同一个库中)指分片规则一致的主表和子表。例如:t_order表和t_order_item表,均按照order_id分片,则此两张表互为绑定表关系。

  • 分片键(ShardingColumn):分片字段用于将数据库(表)水平拆分的字段,支持单字段及多字段分片。例如上例中的order_id。一般在业务中经常查询使用的字段会作为分片键

3、Sharding-JDBC执行原理

参考官网-内部剖析

4、sharding-jdbc分片方式介绍

参考:https://shardingsphere.apache.org/document/legacy/4.x/document/cn/manual/sharding-jdbc/configuration/config-spring-boot/

sharding-jdbc实现数据分片有4种策略:

  • inline模式

  • 通过groovy表达式来表示分库分表的策略;db0 ├── t_order_1 └── t_order_2db1 ├── t_order_1 └── t_order_2 表达式:db${0..1}.t_order_${1..2} 通过一个表达式代表4个数据节点 t_order_${orderId % 2 + 1 } 表的分片规则

  • 使用最简单,开发成本比较低;

  • 只能使用单个字段作为分片键;

  • 基于行表达式定义分片规则;

  • standard标准分片模式

  • 用户可通过代码自定义复杂的分片策略;

  • 同样只能使用单个字段作为分片键;

  • complex复合分片模式

  • 用于多分片键的复合分片策略(多片键)

  • Hint强制分片模式

  • 不指定片键,通过代码动态指定路由规则

  • 强制分片策略(强制路由)