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

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

适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
支持任何第三方的数据库连接池,如:DBCP,C3P0,BoneCP,Druid,HikariCP等。
支持任意实现JDBC规范的数据库。目前支持 MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。

二、ShardingSphere-JDBC的核心功能
数据分片
1.分库分表
2.读写分离
3.分片策略可定制
4.无中心化分布式主键(snowflake算法)

分布式事务
1.标准化事务接口
2.两阶段提交事务
3.柔性事务

数据库治理
1.配置动态化
2.编排和治理
3.数据脱敏
4.可视化链路追踪

三、概念介绍
Sharding JDBC的整个执行过程涉及到一些概念:
1、逻辑表
水平拆分的数据表的总称。例如:我们将用户表根据某种策略拆分为n张表,分别是 t_user_0 、 t_user_1 、、t_user_n,他们的逻辑表名为 t_order。

2、真实表
在分片的数据库中真实存在的物理表。即上述示例中的t_user_0 、 t_user_1 、、t_user_n。

3、数据节点
数据分片的最小物理单元。由数据源名称和数据表组成,例如: DS_0.t_user_0、DS_0.t_user_1、DS_1.t_user_0、DS_1.t_user_1。

4、绑定表-联表查询防止出现笛卡尔积现象
指分片规则一致的主表和子表。例如: 有t_user和 t_user_detail两个逻辑表,两个表都按照user_id分片,绑定表之间的分区
键完全相同,则此两张表互为绑定表关系。绑定表之间的多表关联查询不会出现笛卡尔积关联,关联查询效率将大
大提升。举例说明,如果逻辑SQL为:

SELECT d.* FROM t_user u JOIN t_user_detail d ON u.user_id=d.user_id WHERE u.user_id in (1,2);

在不配置绑定表关系时,假设分片键 user_id 将数值1路由至第0片,将数值2路由至第1片,那么路由后的SQL
应该为4条,它们呈现为笛卡尔积:

SELECT d.* FROM t_user_0 u JOIN t_user_detail_0 d ON u.user_id=d.user_id WHERE u.user_id in (1,2);
SELECT d.* FROM t_user_0 u JOIN t_user_detail_1 d ON u.user_id=d.user_id WHERE u.user_id in (1,2);
SELECT d.* FROM t_user_1 u JOIN t_user_detail_0 d ON u.user_id=d.user_id WHERE u.user_id in (1,2);
SELECT d.* FROM t_user_1 u JOIN t_user_detail_1 d ON u.user_id=d.user_id WHERE u.user_id in (1,2);

在配置绑定表关系后,路由的SQL应该为2条:

SELECT d.* FROM t_user_0 u JOIN t_user_detail_0 d ON u.user_id=d.user_id WHERE u.user_id in (1,2);
SELECT d.* FROM t_user_1 u JOIN t_user_detail_1 d ON u.user_id=d.user_id WHERE u.user_id in (1,2);

5、广播表
也可以叫公共表,指所有的分片数据源中都存在的表,表结构和表中的数据在每个数据库中均完全一致。适用于数据量不大且需要与海量数据的表进行关联查询的场景,例如:字典表。

6、分片键
用于分片的数据库字段,是将数据库(表)水平拆分的关键字段。例:将用户表中的用户ID取模分片,则用户ID为分片字段。SQL中如果无分片字段,将执行全路由,性能较差。除了对单分片字段的支持,ShardingJDBC也支持根据多个字段进行分片。

7、分片算法
通过分片算法将数据分片,支持通过 = 、BETWEEN和IN分片。分片算法需要应用方开发者自行实现,可实现的灵活度非常高。包括:精确分片算法 、范围分片算法 ,复合分片算法 等。例如:where user_id = ? 将采用精确分片算法,where user_id in (?,?,?)将采用精确分片算法,where user_id BETWEEN ? and ? 将采用范围分片算法,复合分片算法用于分片键有多个复杂情况。

8、分片策略
包含分片键和分片算法,由于分片算法的独立性,将其独立抽离。真正可用于分片操作的是分片键 + 分片算法,也就是分片策略。内置的分片策略大致可分为取模、哈希、范围、标签、时间等。由用户方配置的分片策略则更加灵活,常用的使用行表达式配置分片策略,它采用Groovy表达式表示,如: t_user_$->{user_id % 50} 表示t_user表根据user_id模50,而分成50张表,表名称为 t_user_0 到 t_user_49。

9、自增主键生成策略
通过在客户端生成自增主键替换以数据库原生自增主键的方式,做到分布式主键无重复。

四、ShardingSphere-JDBC执行原理

上图所示,描述了Sharding JDBC的大致执行原理图。

1、SQL解析
当Sharding-JDBC接受到一条SQL语句时,会陆续执行SQL解析 -> 查询优化 -> SQL路由 -> SQL改写 -> SQL执行 ->结果归并 ,最终返回执行结果。
SQL解析过程包括词法解析和语法解析。词法解析器用于将SQL拆解为不可再分的原子符号,称为Token。并根据不同数据库方言所提供的字典,将其归类为关键字、表达式、字面量和操作符。再使用语法解析器将SQL转换为抽象语法树。
比如,有以下查询SQL:

SELECT user_id,name FROM t_user WHERE status = 'NORMAL' AND age > 18;

解析之后的为抽象语法树见下图:

通过对抽象语法树的遍历去提炼分片所需的上下文,并标记有可能需要SQL改写的位置。 供分片使用的解析上下文包含查询选择项(Select Items)、表信息(Table)、分片条件(Sharding Condition)、自增主键信息(Auto increment Primary Key)、排序信息(Order By)、分组信息(Group By)以及分页信息(Limit、Rownum、Top)。
2、SQL路由
SQL路由就是把针对逻辑表的数据操作映射到对数据结点操作的过程。根据解析上下文匹配数据库和表的分片策略,并生成路由路径。对于携带分片键的SQL,根据分片键操作符不同可以划分为单片路由(分片键的操作符是等号)、多片路由(分片键的操作符是IN)和范围路由(分片键的操作符是BETWEEN),不携带分片键的SQL则采用广播路由。根据分片键进行路由的场景可分为直接路由、标准路由、笛卡尔路由等。

标准路由
标准路由是Sharding-Jdbc最为推荐使用的分片方式,它的适用范围是不包含关联查询或仅包含绑定表之间关联查询的SQL。 当分片运算符是等于号时,路由结果将落入单库(表),当分片运算符是BETWEEN或IN时,则路由结果不一定落入唯一的库(表),因此一条逻辑SQL最终可能被拆分为多条用于执行的真实SQL。

笛卡尔路由
笛卡尔路由是最复杂的情况,它无法根据绑定表的关系定位分片规则,因此非绑定表之间的关联查询需要拆解为笛卡尔积组合执行。

全库表路由
对于不携带分片键的SQL,则采取广播路由的方式。根据SQL类型又可以划分为全库表路由、全库路由、全实例路由、单播路由和阻断路由这5种类型。其中全库表路由用于处理对数据库中与其逻辑表相关的所有真实表的操作,主要包括不带分片键的DQL(数据查询)和DML(数据操纵),以及DDL(数据定义)等。

3、SQL改写
我们在开发过程中面向逻辑表书写的SQL并不能够直接在真实的数据库中执行,需要将逻辑SQL改写为能在真实数据库中可以正确执行的SQL。
举一个简单的例子,若逻辑SQL为:

SELECT name FROM t_user WHERE user_id=1;

假设该SQL配置分片键user_id,并且user_id=1的情况将路由至分片表1。那么改写之后的SQL应该为:

SELECT name FROM t_user_1 WHERE user_id=1;

还有一种情况,当Sharding-JDBC需要在结果归并时获取相应数据,但该数据并未能通过查询的SQL返回。 这种情况主要是针对GROUP BY和ORDER BY。结果归并时,需要根据GROUP BY和ORDER BY的字段项进行分组和排序,但如果原始SQL的选择项中若并未包含分组项或排序项,则需要对原始SQL进行改写。比如有这样一个逻辑SQL:

SELECT name FROM t_user ORDER BY create_time;

由于原始SQL中并不包含需要在结果归并中需要获取的,因此需要对SQL进行补列改写。补列之后的SQL是:

SELECT name, create_time FROM t_user ORDER BY create_time;

4、SQL执行
Sharding-JDBC采用一套自动化的执行引擎,负责将路由和改写完成之后的真实SQL安全且高效发送到底层数据源执行。 它不是简单地将SQL通过JDBC直接发送至数据源执行,也不是直接将执行请求放入线程池去并发执行。它更关注平衡数据源连接创建以及内存占用所产生的消耗,以及最大限度地合理利用并发等问题。 执行引擎的目标是自动化的平衡资源控制与执行效率,他能在以下两种模式自适应切换:

内存限制模式
使用此模式的前提是, Sharding-JDBC对一次操作所耗费的数据库连接数量不做限制。 如果实际执行的SQL需要对某数据库实例中的200张表做操作,则对每张表创建一个新的数据库连接,并通过多线程的方式并发处理,以达成执行效率最大化。
连接限制模式
使用此模式的前提是,Sharding-JDBC严格控制对一次操作所耗费的数据库连接数量。 如果实际执行的SQL需要对某数据库实例中的200张表做操作,那么只会创建唯一的数据库连接,并对其200张表串行处理。 如果一次操作中的分片散落在不同的数据库,仍然采用多线程处理对不同库的操作,但每个库的每次操作仍然只创建一个唯一的数据库连接。
内存限制模式适用于OLAP操作,可以通过放宽对数据库连接的限制提升系统吞吐量; 连接限制模式适用于OLTP操作,OLTP通常带有分片键,会路由到单一的分片,因此严格控制数据库连接,以保证在线系统数据库资源能够被更多的应用所使用,是明智的选择。
5、结果归并
将从各个数据节点获取的多数据结果集,组合成为一个结果集并正确的返回至请求客户端,称为结果归并。
结果归并从功能划分可分为:遍历、排序、分组、分页和聚合5种类型,它们是组合而非互斥的关系。
遍历归并
它是最为简单的归并方式。 只需将多个数据结果集合并为一个单向链表即可。在遍历完成链表中当前数据结果集之后,将链表元素后移一位,继续遍历下一个数据结果集即可。
排序归并
由于在SQL中存在ORDER BY语句,因此每个数据结果集自身是有序的,因此只需要将数据结果集当前游标指向的数据值进行排序即可。 这相当于对多个有序的数组进行排序,归并排序是最适合此场景的排序算法。

ShardingSphere在对排序的查询进行归并时,将每个结果集的当前数据值进行比较(通过实现Java的Comparable接口完成),并将其放入优先级队列。 每次获取下一条数据时,只需将队列顶端结果集的游标下移,并根据新游标重新进入优先级排序队列找到自己的位置即可。

通过一个例子来说明ShardingSphere的排序归并,下图是一个通过分数进行排序的示例图。 图中展示了3张表返回的数据结果集,每个数据结果集已经根据分数排序完毕,但是3个数据结果集之间是无序的。 将3个数据结果集的当前游标指向的数据值进行排序,并放入优先级队列,t_score_0的第一个数据值最大,t_score_2的第一个数据值次之,t_score_1的第一个数据值最小,因此优先级队列根据t_score_0,t_score_2和t_score_1的方式排序队列。

下图则展现了进行next调用的时候,排序归并是如何进行的。 通过图中我们可以看到,当进行第一次next调用时,排在队列首位的t_score_0将会被弹出队列,并且将当前游标指向的数据值(也就是100)返回至查询客户端,并且将游标下移一位之后,重新放入优先级队列。 而优先级队列也会根据t_score_0的当前数据结果集指向游标的数据值(这里是90)进行排序,根据当前数值,t_score_0排列在队列的最后一位。 之前队列中排名第二的t_score_2的数据结果集则自动排在了队列首位。

在进行第二次next时,只需要将目前排列在队列首位的t_score_2弹出队列,并且将其数据结果集游标指向的值返回至客户端,并下移游标,继续加入队列排队,以此类推。 当一个结果集中已经没有数据了,则无需再次加入队列。

可以看到,对于每个数据结果集中的数据有序,而多数据结果集整体无序的情况下,ShardingSphere无需将所有的数据都加载至内存即可排序。 它使用的是流式归并的方式,每次next仅获取唯一正确的一条数据,极大的节省了内存的消耗。

聚合归并
无论是流式分组归并还是内存分组归并,对聚合函数的处理都是一致的。 除了分组的SQL之外,不进行分组的SQL也可以使用聚合函数。 因此,聚合归并是在之前介绍的归并类的之上追加的归并能力,即装饰者模式。聚合函数可以归类为比较、累加和求平均值这3种类型。
比较类型的聚合函数是指MAX和MIN。它们需要对每一个同组的结果集数据进行比较,并且直接返回其最大或最小值即可。
累加类型的聚合函数是指SUM和COUNT。它们需要将每一个同组的结果集数据进行累加。
求平均值的聚合函数只有AVG。它必须通过SQL改写的SUM和COUNT进行计算。

结果归并从结构划分可分为:流式归并、内存归并和装饰者归并。流式归并和内存归并是互斥的,装饰者归并可以在流式归并和内存归并之上做进一步的处理。

内存归并 很容易理解,他是将所有分片结果集的数据都遍历并存储在内存中,再通过统一的分组、排序以及聚合等
计算之后,再将其封装成为逐条访问的数据结果集返回

流式归并 是指每一次从数据库结果集中获取到的数据,都能够通过游标逐条获取的方式返回正确的单条数据,它与
数据库原生的返回结果集的方式最为契合。遍历、排序以及流式分组都属于流式归并的一种。

ShardingSphere-JDBC执行原理相关推荐

  1. ShardingSphere JDBC 语句执行初探

    简介 在前几篇文中,我们基于源码就ShardingSphere的核心功能给运行了一遍,本篇文章开始,我们开始探索源码,看看ShardingSphere是如何进行工作的 概览 开始之前,我们先思考这次探 ...

  2. spring Mvc 执行原理 及 xml注解配置说明 (六)

    Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...

  3. ShardingSphere JDBC 分库分表 读写分离 数据加密

    简介 在上篇文章中,在本地搭建了运行环境,本地来体验下ShardingSphere JDBC的三个功能:分库分表.读写分离.数据加密 示例运行 首先把概念先捋一捋,参考下面的文档: 数据分片 读写分离 ...

  4. Mybatis原理——执行原理详解

    总结于B站鲁班大叔视频:https://www.bilibili.com/video/BV1Tp4y1X7FM?p=13&spm_id_from=pageDriver 概述 JDBC的执行流程 ...

  5. Java MyBatis的介绍及其执行原理

    写在前面 ??MyBatis学习 ??今天我们进行MyBatis框架的学习,认识MyBatis及其执行原理,感谢你的阅读,内容若有不当之处,希望大家多多指正,一起进步!!! 如果觉得博主文章还不错,可 ...

  6. java调用exe_要精通Java,先研究它的执行原理

    对于任何一门语言,要想达到精通的水平,研究它的执行原理(或者叫底层机制)不失为一种良好的方式. 在本篇文章中,将重点研究java源代码的执行原理,即从程序员编写JAVA源代码,到最终形成产品,在整个过 ...

  7. ssm中怎么使tomcat一起动就执行一个controller_【200期】面试官:你能简单说说 SpringMVC 的执行原理吗?...

    点击上方"Java面试题精选",关注公众号 面试刷图,查缺补漏 >>号外:往期面试题,10篇为一个单位归置到本公众号菜单栏->面试题,有需要的欢迎翻阅 阶段汇总集 ...

  8. jdbc执行Statement接口的步骤

    jdbc执行Statement接口的步骤如下: 1)驱动注册程序: Class.forName(com.mysql.jdbc.Driver); 2)获取连接对象: Connection conn = ...

  9. python代码怎么运行-Python程序执行原理,python程序怎么运行的?

    随着人工智能时代的来临,python成为了人们学习编程的首先语言.那么,python程序的程序的执行原理什么呢?python程序怎么运行的?我们下面来介绍下. 我们都知道,使用CC++之类的编译性语言 ...

最新文章

  1. 拼多多面试|如何用 Redis 统计独立用户访问量?
  2. 计算机网络 DNS域名
  3. python多线程调用携程,进程、线程和携程的通俗解释【刘新宇Python】
  4. Centos 7 查看内存占用情况相关命令
  5. ARP协议在同网段及跨网段下的工作原理
  6. 图灵奖颁给深度学习三巨头,他们曾是一小撮顽固的“蠢货”
  7. 从Python.org下载Python安装包下载很慢
  8. idea安装svn插件
  9. 电气simulink常用模块_重庆台达PLC控制柜施工技术标准 - 重庆电工电气
  10. vue代码怎么变成小程序_从项目中由浅入深的学习vue,微信小程序和快应用 (1)
  11. 《阵列信号处理及MATLAB实现》绪论、矩阵代数相关内容总结笔记
  12. findIndex()
  13. linux 本地项目文件挂载到虚拟机上面,不用在本地编辑后再上传到虚拟机上,实现高效率开发
  14. tensorflow one-hot独热编码
  15. Fastdata极数:2019年中国即时配送行业发展分析报告
  16. java 实现自定义数据模板下载Execl
  17. 网络安全之反射放大型DDOS
  18. Apache Hudi 数据湖概述
  19. VOCS在线监测系统 VOCS监测环保数采仪
  20. [编]在Web站点中创建和使用Rss源

热门文章

  1. php天花板好吗,天花板的钢筋都露出来了,还以为不要紧!老公后怕:安全隐患太大...
  2. iOS UICollectionView 高级用法(长按cell移动重新排列)
  3. Android Framework 简介
  4. 使用Spring Security和Thymeleaf进行CSRF保护
  5. 触发器之宏观把握与微观总结
  6. 一个测试人员如何变成测试架构师
  7. 蓝桥杯 扑克牌“魔术
  8. 把数字翻译成字符串python_剑指offer-46把数字翻译成字符串-python
  9. PageUtil 分页工具类
  10. ubuntu 14.04 重启网卡