详解Sharding-JDBC的概念

核心概念

分片

一般我们在提到分库分表的时候,大多是以水平切分模式(水平分库、分表)为基础来说的,数据分片将原本一张数据量较大的表 t_order 拆分生成数个表结构完全一致的小数据量表 t_order_0、t_order_1、···、t_order_n,每张表只存储原大表中的一部分数据,当执行一条SQL时会通过 分库策略、分片策略 将数据分散到不同的数据库、表内。

在这里插入图片描述

数据节点

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

逻辑表

逻辑表是指一组具有相同逻辑和数据结构表的总称。比如我们将订单表拆分成 t_order_0 ··· t_order_9 等 10 张表。此时我们会发现分库分表以后数据库中已不在有这张表,取而代之的是 ,但我们在代码中写 依然按 来写。此时 就是这些拆分表的逻辑表。

真实表

真实表也就是上边提到的 数据库中真实存在的物理表。

分片键

用于分片的数据库字段。我们将 表分片以后,当执行一条SQL时,通过对字段 order_id 取模的方式来决定,这条数据该在哪个数据库中的哪个表中执行,此时 字段就是 表的分片健。

在这里插入图片描述

这样以来同一个订单的相关数据就会存在同一个数据库表中,大幅提升数据检索的性能,不仅如此 sharding-jdbc 还支持根据多个字段作为分片健进行分片。

分片算法

上边我们提到可以用分片健取模的规则分片,但这只是比较简单的一种,在实际开发中我们还希望用 >=、<=、>、<、BETWEEN 和 IN 等条件作为分片规则,自定义分片逻辑,这时就需要用到分片策略与分片算法。

从执行 SQL 的角度来看,分库分表可以看作是一种路由机制,把 SQL 语句路由到我们期望的数据库或数据表中并获取数据,分片算法可以理解成一种路由规则。

咱们先捋一下它们之间的关系,分片策略只是抽象出的概念,它是由分片算法和分片健组合而成,分片算法做具体的数据分片逻辑。

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

以下是 4 种分片算法:

精确分片算法

精确分片算法(PreciseShardingAlgorithm)用于单个字段作为分片键,SQL中有 = 与 等条件的分片,需要在标准分片策略(StandardShardingStrategy )下使用。

范围分片算法

范围分片算法(RangeShardingAlgorithm)用于单个字段作为分片键,SQL 中有 BETWEEN AND、、、、 )下使用。

复合分片算法

复合分片算法(ComplexKeysShardingAlgorithm)用于多个字段作为分片键的分片操作,同时获取到多个分片健的值,根据多个字段处理业务逻辑。需要在复合分片策略(ComplexShardingStrategy )下使用。

Hint分片算法

Hint分片算法(HintShardingAlgorithm)稍有不同,上边的算法中我们都是解析语句提取分片键,并设置分片策略进行分片。但有些时候我们并没有使用任何的分片键和分片策略,可还想将 SQL 路由到目标数据库和表,就需要通过手动干预指定 SQL 的目标数据库和表信息,这也叫强制路由。

分片策略

上边讲分片算法的时候已经说过,分片策略是一种抽象的概念,实际分片操作的是由分片算法和分片健来完成的。

以下是 4 种分片策略:

标准分片策略

标准分片策略适用于单分片键,此策略支持 PreciseShardingAlgorithm 和 RangeShardingAlgorithm两个分片算法。

其中 是必选的,用于处理和的分片。 是可选的,用于处理, , ,, 条件分片,如果不配置,SQL中的条件等将按照全库路由处理。

复合分片策略

复合分片策略,同样支持对SQL语句中的 ,, , , ,和的分片操作。不同的是它支持多分片键,具体分配片细节完全由应用开发者实现。

行表达式分片策略

行表达式分片策略,支持对 SQL 语句中的和的分片操作,但只支持单分片键。这种策略通常用于简单的分片,不需要自定义分片算法,可以直接在配置文件中接着写规则。

t_order_$->{t_order_id % 4} 代表 对其字段 t_order_id取模,拆分成 4 张表,而表名分别是到 t_order_3。

Hint分片策略

Hint 分片策略,对应上边的 Hint 分片算法,通过指定分片健而非从中提取分片健的方式进行分片的策略。

分布式主键

数据分后,不同数据节点成全局唯主键是常棘的问题,同个逻辑表()内的不同真实表()之间的增键由于法互相感知而产重复主键。

尽管可通过设置增主键 初始值和步的式避免ID碰撞,但这样会使维护成本加大,乏完整性和可扩展性。如果后去需要增加分片表的数量,要逐一修改分片表的步长,运维成本非常高,所以不建议这种方式。

实现分布式主键成器的方式很多,具体可以百度,网上有很多

为了让上手更加简单,ApacheShardingSphere 内置了 UUID、SNOWFLAKE 两种分布式主键成器,默认使雪花算法(snowflake)成 64 bit的整型数据。不仅如此它还抽离出分布式主键成器的接口,便我们实现定义的增主键成算法。

广播表

广播表:存在于所有的分片数据源中的表,表结构和表中的数据在每个数据库中均完全一致。一般是为字典表或者配置表 t_config,某个表一旦被配置为广播表,只要修改某个数据库的广播表,所有数据源中广播表的数据都会跟着同步。

绑定表

绑定表:那些分片规则一致的主表和子表。比如: 订单表 t_order 和 t_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_0 o JOIN t_order_item_1 i ON o.order_id=i.order_id
  • SELECT * FROM t_order_1 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_item_0 表关联即可。

在这里插入图片描述
一张表经过分库分表后被拆分成多个子表,并分散到不同的数据库中,在不修改原业务 SQL 的前提下,Sharding-JDBC 就必须对 SQL 进行一些改造才能正常执行。

SQL执行流程

大致的执行流程:SQL 解析 -> 执器优化 -> SQL 路由 -> SQL 改写 -> SQL 执 -> 结果归并六步组成,而它每个步骤都做了些什么呢?

在这里插入图片描述

SQL 解析

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

SELECT order_no,price FROM t_order_ where user_id = 10086 and order_status > 0

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

在这里插入图片描述

查询优化

执器优化对SQL分片条件进行优化,处理像关键字 OR这种影响性能的坏味道。

SQL 路由

SQL 路由通过解析分片上下文,匹配到用户配置的分片策略,并生成路由路径。简单点理解就是可以根据我们配置的分片策略计算出 SQL 该在哪个库的哪个表中执行,而 SQL 路由又根据有无分片健区分出 分片路由和广播路由。

在这里插入图片描述

标准路由

标准路由是最推荐也是最为常的分式,它的适范围是不包含关联查询或仅包含绑定表之间关联查询的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)

直接路由

直接路由是通过使用 HintAPI 直接将 SQL 路由到指定库表的一种分方式,而且直接路由可以于分键不在SQL中的场景,还可以执包括查询、定义函数等复杂情况的任意SQL。

比如根据 t_order_id 字段为条件查询订单,此时希望在不修改 SQL 的前提下,加上 user_id 作为分片条件就可以使用直接路由。

笛卡尔积路由

笛卡尔路由是由绑定表之间的关联查询产生的,查询性能较低尽量避免走此路由模式。

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

全库表路由

全库表路由针对的是数据库 DQL 和 DML,以及 DDL 等操作,当我们执行一条逻辑表 t_orderSQL 时,在所有分片库中对应的真实表 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 改写成可以在真实数据库中可以正确执行的语句。比如查询 t_order 订单表,我们实际开发中 SQL 是按逻辑表 t_order 写的。

SELECT * FROM t_order

但分库分表以后真实数据库中 t_order 表就不存在了,而是被拆分成多个子表 t_order_n 分散在不同的数据库内,还按原 SQL 执行显然是行不通的,这时需要将分表配置中的逻辑表名称改写为路由之后所获取的真实表名称。

SELECT * FROM t_order_n

SQL执行

将路由和改写后的真实 SQL 安全且高效发送到底层数据源执行。但这个过程并不是简单的将 SQL 通过JDBC 直接发送至数据源执行,而是平衡数据源连接创建以及内存占用所产生的消耗,它会自动化的平衡资源控制与执行效率。

### 结果归并

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

关于分库分表代码可以看我这篇分享的文章 sharding-JDBC分库分表配置分析

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值