关于分库分表:分库分表的-21-条法则hold-住

37次阅读

共计 7729 个字符,预计需要花费 20 分钟才能阅读完成。

大家好,我是小富~

(一)好好的零碎,为什么要分库分表?

本文是《分库分表 ShardingSphere5.x 原理与实战》系列的第二篇文章,间隔上一篇文章曾经过来良久了,羞愧羞愧~

还是不焦急实战,咱们先介绍下在分库分表架构施行过程中,会接触到的一些通用概念,理解这些概念可能帮忙了解市面上其余的分库分表工具,只管它们的实现办法可能存在差别,但整体思路基本一致。因而,在开始实际操作之前,咱们有必要先把握这些通用概念,以便更好地了解和利用分库分表技术。

咱们联合具体业务场景,以 t_order 表为例进行架构优化。因为数据量曾经达到亿级别,查问性能重大降落,因而咱们采纳了分库分表技术来解决这个问题。具体而言,咱们将本来的单库分成了两个库,别离为 DB_1DB_2,并在每个库中再次进行分表处理,生成 t_order_1t_order_2两张表,实现对订单表的分库分表处理。

数据分片

通常咱们在提到分库分表的时候,大多是以程度切分模式(程度分库、分表)为根底来说的,数据分片它将本来一张数据量较大的表 t_order 拆分生成数个 表构造完全一致 的小数据量表(拆分表)t_order_0t_order_1、···、t_order_n,每张表只存储原大表中的一部分数据。

数据节点

数据节点是数据分片中一个不可再分的最小单元(表),它由数据源名称和数据表组成,例如上图中 DB_1.t_order_1DB_2.t_order_2 就示意一个数据节点。

逻辑表

逻辑表是指具备雷同构造的程度拆分表的逻辑名称。

比方咱们将订单表 t_order 分表拆分成 t_order_0 ··· t_order_9 等 10 张表,这时咱们的数据库中曾经不存在 t_order这张表,取而代之的是若干的 t_order_n 表。

分库分表通常对业务代码都是无侵入式的,开发者只专一于业务逻辑 SQL 编码,咱们在代码中 SQL 仍然按 t_order来写,而在执行逻辑 SQL 前将其解析成对应的数据库实在执行的 SQL。此时 t_order 就是这些拆分表的 逻辑表

业务逻辑 SQL

select * from t_order where order_no='A11111'

实在执行 SQL

select * from DB_1.t_order_n where order_no='A11111'

实在表

实在表就是在数据库中实在存在的物理表DB_1.t_order_n

播送表

播送表是一类非凡的表,其表构造和数据在所有分片数据源中均完全一致。与拆分表相比,播送表的数据量较小、更新频率较低,通常用于字典表或配置表等场景。因为其在所有节点上都有正本,因而能够大大降低 JOIN 关联查问的网络开销,进步查问效率。

须要留神的是,对于播送表的批改操作须要保障同步性,以确保所有节点上的数据保持一致。

播送表的特点

  • 在所有分片数据源中,播送表的数据完全一致。因而,对播送表的操作(如插入、更新和删除)会实时在每个分片数据源中执行一遍,以保证数据的一致性。
  • 对于播送表的查问操作,仅须要在任意一个分片数据源中执行一次即可。
  • 与任何其余表进行 JOIN 操作都是可行的,因为因为播送表的数据在所有节点上均统一,所以能够拜访到任何一个节点上的雷同数据。

什么样的表能够作为播送表呢?

订单管理系统中,往往须要查问统计某个城市地区的订单数据,这就会波及到省份地区表 t_city 与订单流水表 DB_n.t_order_n 进行 JOIN 查问,因而能够思考将省份地区表设计为 播送表 ,核心理念就是 防止跨库 JOIN 操作

留神:上边咱们提到播送表在数据插入、更新与删除会实时在每个分片数据源均执行,也就是说如果你有 1000 个分片数据源,那么批改一次播送表就要执行 1000 次 SQL,所以尽量不在并发环境下和业务顶峰时进行,免得影响零碎的性能。

单表

单表指所有的分片数据源中仅惟一存在的表(没有分片的表),实用于数据量不大且无需分片的表。

如果一张表的数据量预估在千万级别,且没有与其余拆分表进行关联查问的需要,倡议将其设置为单表类型,存储在默认分片数据源中。

分片键

分片键决定了数据落地的地位,也就是数据将会被调配到哪个数据节点上存储。因而,分片键的抉择十分重要。

比方咱们将 t_order 表进行分片后,当插入一条订单数据执行 SQL 时,须要通过解析 SQL 语句中指定的分片键来计算数据应该落在哪个分片中。以表中 order_no 字段为例,咱们能够通过对其取模运算(比方 order_no % 2)来失去分片编号,而后依据分片编号调配数据到对应的数据库实例(比方 DB_1DB_2)。拆分表也是同理计算。

在这个过程中,order_no 就是 t_order 表的分片键。也就是说,每一条订单数据的 order_no 值决定了它应该寄存的数据库实例和表。抉择一个适宜作为分片键的字段能够更好地利用程度分片带来的性能晋升。

这样同一个订单的相干数据就会落在同一个数据库、表中,查问订单时同理计算,就可间接定位数据地位,大幅晋升数据检索的性能,防止了全库表扫描。

不仅如此 ShardingSphere 还反对依据多个字段作为分片健进行分片,这个在后续对应章节中会具体讲。

分片策略

分片策略来指定应用哪种分片算法、抉择哪个字段作为分片键以及如何将数据调配到不同的节点上。

分片策略是由 分片算法 分片健 组合而成,分片策略中能够应用多种分片算法和对多个分片键进行运算。

分库、分表的分片策略配置是绝对独立的,能够各自应用不同的策略与算法,每种策略中能够是多个分片算法的组合,每个分片算法能够对多个分片健做逻辑判断。

分片算法

分片算法则是用于对分片键进行运算,将数据划分到具体的数据节点中。

罕用的分片算法有很多:

  • 哈希分片:依据分片键的哈希值来决定数据应该落到哪个节点上。例如,依据用户 ID 进行哈希分片,将属于同一个用户的数据调配到同一个节点上,便于后续的查问操作。
  • 范畴分片:分片键值按区间范畴调配到不同的节点上。例如,依据订单创立工夫或者地理位置来进行分片。
  • 取模分片:将分片键值对分片数取模,将后果作为数据应该调配到的节点编号。例如,order_no % 2 将订单数据分到两个节点之一。
  • …..

理论业务开发中分片的逻辑要简单的多,不同的算法实用于不同的场景和需要,须要依据理论状况进行抉择和调整。

绑定表

绑定表是那些具备雷同分片规定的一组分片表,因为分片规定统一所产生的的数据落地地位雷同,在 JOIN 联结查问时能无效 防止跨库 操作。

比方:t_order 订单表和 t_order_item 订单项目表,都以 order_no 字段作为分片键,并且应用 order_no 进行关联,因而两张表互为绑定表关系。

应用绑定表进行多表关联查问时,必须应用分片键进行关联,否则会呈现笛卡尔积关联或跨库关联,从而影响查问效率。

当应用 t_ordert_order_item 表进行多表联结查问,执行如下联结查问的逻辑 SQL。

SELECT * FROM t_order o JOIN t_order_item i ON o.order_no=i.order_no

如果不配置绑定表关系,两个表的数据地位不确定就会全库表查问,呈现笛卡尔积关联查问,将产生如下四条SQL

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_no=i.order_no 
SELECT * FROM t_order_0 o JOIN t_order_item_1 i ON o.order_no=i.order_no 
SELECT * FROM t_order_1 o JOIN t_order_item_0 i ON o.order_no=i.order_no 
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_no=i.order_no 

而配置绑定表关系后再进行关联查问时,分片规定统一产生的数据就会落到同一个库表中,那么只需在以后库中 t_order_nt_order_item_n 表关联即可。

SELECT * FROM t_order_0 o JOIN t_order_item_0 i ON o.order_id=i.order_id 
SELECT * FROM t_order_1 o JOIN t_order_item_1 i ON o.order_id=i.order_id 

留神:在关联查问时 t_order 它作为整个联结查问的主表。所有相干的路由计算都只应用主表的策略,t_order_item 表的分片相干的计算也会应用 t_order 的条件,所以要保障绑定表之间的分片键要完全相同。

SQL 解析

分库分表后在利用层面执行一条 SQL 语句时,通常须要通过以下六个步骤:SQL 解析 -> 执⾏器优化 -> SQL 路由 -> SQL 改写 -> SQL 执⾏ -> 后果归并

SQL 解析过程分为 词法解析 语法解析 两步,比方下边查问用户订单的 SQL,先用词法解析将这条 SQL 拆解成不可再分的原子单元。在依据不同数据库方言所提供的字典,将这些单元归类为关键字,表达式,变量或者操作符等类型。

SELECT order_no FROM t_order where  order_status > 0  and user_id = 10086 

接着语法解析会将拆分后的 SQL 关键字转换为形象语法树,通过对形象语法树遍历,提炼出分片所需的上下文,上下文蕴含查问字段信息(Field)、表信息(Table)、查问条件(Condition)、排序信息(Order By)、分组信息(Group By)以及分页信息(Limit)等,并标记出 SQL 中有可能须要改写的地位。

执⾏器优化

执⾏器优化是依据 SQL 查问特点和执行统计信息,抉择最优的查问打算并执行,比方 user_id 字段有索引,那么会调整两个查问条件的地位,次要是进步 SQL 的执行效率。

SELECT order_no FROM t_order where user_id = 10086 and order_status > 0

SQL 路由

通过上边的 SQL 解析失去了分片上下文数据,在匹配用户配置的分片策略和算法,就能够运算生成路由门路,将 SQL 语句路由到相应的数据节点上。

简略点了解就是拿到分片策略中配置的分片键等信息,在从 SQL 解析后果中找到对应分片键字段的值,计算出 SQL 该在哪个库的哪个表中执行,SQL 路由又依据有无分片健分为 分片路由 播送路由

有分⽚键的路由叫分片路由,细分为间接路由、规范路由和笛卡尔积路由这 3 种类型。

规范路由

规范路由是最举荐也是最为常⽤的分⽚⽅式,它的适⽤范畴是不蕴含关联查问或仅蕴含绑定表之间关联查问的 SQL。

当 SQL 分片健的运算符为 = 时,路由后果将落⼊单库(表),当分⽚运算符是 BETWEEN IN 等范畴时,路由后果则不⼀定落⼊唯⼀的库(表),因而⼀条逻辑 SQL 最终可能被拆分为多条⽤于执⾏的实在 SQL。

SELECT * FROM t_order  where t_order_id in (1,2)

SQL 路由解决后

SELECT * FROM t_order_0  where t_order_id in (1,2)
SELECT * FROM t_order_1  where t_order_id in (1,2)

间接路由

间接路由是间接将 SQL 路由到指定⾄库、表的一种分⽚形式,而且间接路由能够⽤于分⽚键不在 SQL 中的场景,还能够执⾏包含⼦查问、⾃定义函数等简单状况的任意 SQL。

笛卡尔积路由

笛卡尔路由是由⾮绑定表之间的关联查问产生的,比方订单表 t_order 分片键是t_order_id 和用户表 t_user 分片键是t_order_id ,两个表的分片键不同,要做联表查问,会执行笛卡尔积路由,查问性能较低尽量避免走此路由模式。

SELECT * FROM t_order_0 t LEFT JOIN t_user_0 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_0 t LEFT JOIN t_user_1 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_1 t LEFT JOIN t_user_0 u ON u.user_id = t.user_id WHERE t.user_id = 1
SELECT * FROM t_order_1 t LEFT JOIN t_user_1 u ON u.user_id = t.user_id WHERE t.user_id = 1

无分⽚键的路由又叫做播送路由,能够划分为全库表路由、全库路由、全实例路由、单播路由和阻断路由这 5 种类型。

全库表路由

全库表路由针对的是数据库 DQL DML,以及 DDL等操作,当咱们执行一条逻辑表 t_order SQL 时,在所有分片库中对应的实在表 t_order_0 ··· t_order_n 内逐个执行。

全库路由

全库路由次要是对数据库层面的操作,比方数据库 SET 类型的数据库治理命令,以及 TCL 这样的事务管制语句。

对逻辑库设置 autocommit 属性后,所有对应的实在库中都执行该命令。

SET autocommit=0;

全实例路由

全实例路由是针对数据库实例的 DCL 操作(设置或更改数据库用户或角色权限),比方:创立一个用户 order,这个命令将在所有的实在库实例中执行,以此确保 order 用户能够失常拜访每一个数据库实例。

CREATE USER order@127.0.0.1 identified BY '程序员小富';

单播路由

单播路由用来获取某一实在表信息,比方取得表的形容信息:

DESCRIBE t_order; 

t_order 的实在表是 t_order_0 ···· t_order_n,他们的形容构造相齐全同,咱们只需在任意的实在表执行一次就能够。

阻断路由

⽤来屏蔽 SQL 对数据库的操作,例如:

USE order_db;

这个命令不会在实在数据库中执⾏,因为 ShardingSphere 采⽤的是逻辑 Schema(数据库的组织和构造)⽅式,所以无需将切换数据库的命令发送⾄实在数据库中。

SQL 改写

SQL 通过解析、优化、路由后曾经明确分片具体的落地执行的地位,接着就要将基于逻辑表开发的 SQL 改写成能够在实在数据库中能够正确执行的语句。比方查问 t_order 订单表,咱们理论开发中 SQL 是按逻辑表 t_order 写的。

SELECT * FROM t_order

这时须要将分表配置中的逻辑表名称改写为路由之后所获取的实在表名称。

SELECT * FROM t_order_n

SQL 执⾏

将路由和改写后的实在 SQL 平安且高效发送到底层数据源执行。但这个过程并不能将 SQL 一股脑的通过 JDBC 间接发送至数据源执行,需均衡数据源连贯创立以及内存占用所产生的耗费,它会自动化的均衡资源管制与执行效率。

后果归并

将从各个数据节点获取的多数据后果集,合并成一个大的后果集并正确的返回至申请客户端,称为后果归并。而咱们 SQL 中的排序、分组、分页和聚合等语法,均是在归并后的后果集上进行操作的。

分布式主键

数据分⽚后,一个逻辑表(t_order)对应诸多的实在表(t_order_n),它们之间因为⽆法相互感知,主键 ID 都从初始值累加,所以必然会产⽣反复主键 ID,此时主键不再惟一那么对于业务来说也就没意义了。

只管可通过设置表⾃增主键 初始值 步⻓ 的⽅式防止 ID 碰撞,但这样会使保护老本加大,可扩展性差。

这个时候就须要咱们手动为一条数据记录,调配一个全局惟一的 ID,这个 ID 被叫做分布式 ID,而生产这个 ID 的零碎通常被叫做发号器。

大家能够参考我之前公布的这篇文章 9 种分布式 ID 生成计划

数据脱敏

分库分表数据脱敏是一种无效的数据保护措施,能够确保敏感数据的机密性和安全性,缩小数据泄露的危险。

比方,咱们在分库分表时能够指定表的哪些字段为脱敏列,并设置对应的脱敏算法,在数据分片时解析到执行 SQL 中有待脱敏字段,会间接将字段值脱敏后的写入库表内。

对于用户的个人信息,如姓名、地址和电话号码等,能够通过加密、随机化或替换成伪随机数据的形式进行脱敏,以确保用户的隐衷失去爱护。

大家能够参考我之前公布的这篇文章 大厂也在用的 6 种 数据脱敏计划

分布式事务

分布式事务的外围问题是如何实现跨多个数据源的原子性操作。

因为不同的服务通常会应用不同的数据源来存储和治理数据,因而,跨数据源的操作可能会导致数据不一致性或失落的危险。因而,保障分布式事务的一致性是十分重要的。

以订单零碎为例,它须要调用领取零碎、库存零碎、积分零碎等多个零碎,而每个零碎都保护本人的数据库实例,零碎间通过 API 接口替换数据。

为了保障下单后多个零碎同时调用胜利,能够应用 强一致性事务 的 XA 协定,或者 柔性事务 的代表工具 Seata,来实现分布式事务的一致性。这些工具能够帮忙开发人员简化分布式事务的实现,缩小谬误和破绽的呈现,进步零碎的稳定性和可靠性。

通过分库分表之后,问题的难度进一步晋升。本身订单服务,也须要解决跨数据源的操作。这样一来,零碎的复杂度显著减少。因而,不到万不得已的状况下,最好防止采纳分库分表的解决方案。

对于分布式事务具体的介绍,大家能够参考我之前公布的这篇文章 比照 5 种分布式事务计划,还是宠幸了阿里的 Seata(原理 + 实战)

数据迁徙

分库分表后还有个让人头疼的问题,那就是数据迁徙,为了不影响现有的业务零碎,通常会新建数据库集群迁徙数据。将数据从旧集群的数据库、表迁徙到新集群的分库、分表中。这是一个比较复杂的过程,在迁徙过程中须要思考 数据量 数据一致性 迁徙速度 等诸多因素。

迁徙次要针对 存量数据 增量数据 的解决,存量数据指旧数据源中曾经存在且有价值的历史数据,增量数据指当下持续增长以及将来产生的业务数据。

存量数据能够采纳定时、分批次的迁徙,迁徙过程可能会继续几天。

增量数据能够采纳新、旧数据库集群双写模式。待数据迁徙结束,业务验证了数据一致性,利用间接切换数据源即可。

后续咱们会联合三方工具,来演示迁徙的过程。

影子库

什么是影子库(Shadow Table)?

影子库是一个与生产环境数据库构造完全相同的实例,它存在的意义是为了在不影响线上零碎的状况下,验证数据库迁徙或者其余数据库变更操作的正确性,以及全链路压测。影子库中存储的数据是从生产环境中定期复制过去的,然而它不对线上业务产生任何影响,仅用于测试,验证和调试。

在进行数据库降级、版本变更、参数调优等操作前,通过在影子库上模仿这些操作,能够发现潜在的问题,因为测试环境的数据是不牢靠的。

在应用影子库时,须要遵循以下几个准则:

  • 与生产环境数据库的构造应该完全一致,包含表构造、索引、束缚等;
  • 数据要与生产环境保持一致,能够通过定期同步形式实现;
  • 读写操作不会影响生产环境,个别状况下应该禁止在影子库上执行更新、删除等操作;
  • 因为影子库的数据特点,拜访权限应该严格控制,只容许受权人员进行拜访和操作;

总结

本文介绍了对于分库分表架构的 21 个通用概念,对有肯定的理解之后,接下来咱们将进入更深度的内容,包含 读写拆散 数据脱敏 分布式主键 分布式事务 配置核心 注册核心 Proxy 服务 等实战案例的解说和源码剖析。

下期文章将是《分库分表 ShardingSphere5.x 原理与实战》系列的第三篇,《疾速实现分库分表的 2 种形式》

我是小富,下期见~

正文完
 0