https://www.cnblogs.com/fengpinglangjingruma/p/14005759.html
sharding-jdbc
提供了4种分片算法:
1、精确分片算法
精确分片算法(PreciseShardingAlgorithm)用于单个字段作为分片键,SQL中有 =
与 IN
等条件的分片,需要在标准分片策略(StandardShardingStrategy
)下使用。
2、范围分片算法
范围分片算法(RangeShardingAlgorithm)用于单个字段作为分片键,SQL中有 BETWEEN AND
、>
、<
、>=
、<=
等条件的分片,需要在标准分片策略(StandardShardingStrategy
)下使用。
3、复合分片算法
复合分片算法(ComplexKeysShardingAlgorithm)用于多个字段作为分片键的分片操作,同时获取到多个分片健的值,根据多个字段处理业务逻辑。需要在复合分片策略(ComplexShardingStrategy
)下使用。
4、Hint分片算法
Hint分片算法(HintShardingAlgorithm)稍有不同,上边的算法中我们都是解析SQL
语句提取分片键,并设置分片策略进行分片。但有些时候我们并没有使用任何的分片键和分片策略,可还想将 SQL 路由到目标数据库和表,就需要通过手动干预指定SQL的目标数据库和表信息,这也叫强制路由。
分片策略
上边讲分片算法的时候已经说过,分片策略是一种抽象的概念,实际分片操作的是由分片算法和分片健来完成的。
1、标准分片策略
标准分片策略适用于单分片键,此策略支持 PreciseShardingAlgorithm
和 RangeShardingAlgorithm
两个分片算法。
其中 PreciseShardingAlgorithm
是必选的,用于处理 =
和 IN
的分片。RangeShardingAlgorithm
是可选的,用于处理BETWEEN AND
, >
, <
,>=
,<=
条件分片,如果不配置RangeShardingAlgorithm
,SQL中的条件等将按照全库路由处理。
2、复合分片策略
复合分片策略,同样支持对 SQL语句中的 =
,>
, <
, >=
, <=
,IN
和 BETWEEN AND
的分片操作。不同的是它支持多分片键,具体分配片细节完全由应用开发者实现。
3、行表达式分片策略
行表达式分片策略,支持对 SQL语句中的 =
和 IN
的分片操作,但只支持单分片键。这种策略通常用于简单的分片,不需要自定义分片算法,可以直接在配置文件中接着写规则。
t_order_$->{t_order_id % 4}
代表 t_order
对其字段 t_order_id
取模,拆分成4张表,而表名分别是t_order_0
到 t_order_3
。
4、Hint分片策略
Hint分片策略,对应上边的Hint分片算法,通过指定分片健而非从 SQL
中提取分片健的方式进行分片的策略。
分布式主键
ApacheShardingSphere 内置了SNOWFLAKE,成64bit的⻓整型数据。不仅如此它还抽离出分布式主键⽣成器的接口,⽅便我们实现⾃定义的⾃增主键⽣成算法。
广播表
广播表:存在于所有的分片数据源中的表,表结构和表中的数据在每个数据库中均完全一致。一般是为字典表或者配置表 t_config
,某个表一旦被配置为广播表,只要修改某个数据库的广播表,所有数据源中广播表的数据都会跟着同步。
绑定表
绑定表:那些分片规则一致的主表和子表。比如:t_order
订单表和 t_order_item
订单服务项目表,都是按 order_id
字段分片,因此两张表互为绑定表关系。
那绑定表存在的意义是啥呢?
通常在我们的业务中都会使用 t_order
和 t_order_item
等表进行多表联合查询,但由于分库分表以后这些表被拆分成N多个子表。如果不配置绑定表关系,会出现笛卡尔积关联查询,将产生如下四条SQL
。
而配置绑定表关系后再进行关联查询时,只要对应表分片规则一致产生的数据就会落到同一个库中,那么只需 t_order_0
和 t_order_item_0
表关联即可。
注意:在关联查询时 t_order
它作为整个联合查询的主表。所有相关的路由计算都只使用主表的策略,t_order_item
表的分片相关的计算也会使用 t_order
的条件,所以要保证绑定表之间的分片键要完全相同。
三、和JDBC的猫腻
对原有的 DataSource
、Connection
等接口扩展成 ShardingDataSource
、ShardingConnection
,而对外暴露的分片操作接口与 JDBC 规范中所提供的接口完全一致,只要你熟悉 JDBC 就可以轻松应用 Sharding-JDBC 来实现分库分表。
一张表经过分库分表后被拆分成多个子表,并分散到不同的数据库中,在不修改原业务 SQL 的前提下,Sharding-JDBC
就必须对 SQL进行一些改造才能正常执行。
大致的执行流程:SQL 解析
-> 执⾏器优化
-> SQL 路由
-> SQL 改写
-> SQL 执⾏
-> 结果归并
六步组成,一起瞅瞅每个步骤做了点什么。
解析
接着语法解析会将拆分后的SQL转换为抽象语法树,通过对抽象语法树遍历,提炼出分片所需的上下文,上下文包含查询字段信息(Field
)、表信息(Table
)、查询条件(Condition
)、排序信息(Order By
)、分组信息(Group By
)以及分页信息(Limit
)等,并标记出 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)
直接路由
直接路由是通过使用 HintAPI
直接将 SQL路由到指定⾄库表的一种分⽚方式,而且直接路由可以⽤于分⽚键不在SQL中的场景,还可以执⾏包括⼦查询、⾃定义函数等复杂情况的任意SQL。
比如根据 t_order_id
字段为条件查询订单,此时希望在不修改SQL的前提下,加上 user_id
作为分片条件就可以使用直接路由。
笛卡尔积路由
笛卡尔路由是由⾮绑定表之间的关联查询产生的,查询性能较低尽量避免走此路由模式。
无分⽚键的路由又叫做广播路由,可以划分为全库表路由、全库路由、 全实例路由、单播路由和阻断路由这 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改写成可以在真实数据库中可以正确执行的语句。比如查询 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中的排序、分组、分页和聚合等语法,均是在归并后的结果集上进行操作的。
示例
2、分片配置
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-core-common</artifactId>
<version>4.0.0-RC1</version>
</dependency>
五、总结
以上对分库分表中间件 sharding-jdbc
的基础概念做了简单梳理,快速的搭建了一个分库分表案例,但这只是实践分库分表的第一步,下一篇我们会详细的介绍四种分片策略的具体用法和使用场景(必知必会),后边将陆续讲解自定义分布式主键、分布式数据库事务、分布式服务治理,数据脱敏等。