ShardingSphere
在中小企业须要分库分表的时候用的会比较多,由于它维护成本低,不须要额外增派人手;并且目前社区也还一直在开发和维护,还算是比较活跃。java
可是中大型公司通常会选择选用 Mycat 这类 proxy 层方案,由于可能大公司系统和项目很是多,团队很大,人员充足,那么最好是专门弄我的来研究和维护 Mycat,mysql
而后大量项目直接透明使用便可。sql
1、ShardingSphere概念
一、概念
ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy 和 Sharding-Sidecar这3款相互独立的产品组成。数据库
他们均提供标准化的数据分片
、分布式事务
和 数据库治理功能
,可适用于如Java同构、异构语言、云原生等各类多样化的应用场景。数组
如图分布式
二、功能列表
数据分片
ide
- 分库 & 分表 - 读写分离 - 分片策略定制化 - 无中心化分布式主键
分布式事务
函数
- 标准化事务接口 - XA强一致事务 - 柔性事务
数据库治理
spa
- 配置动态化 - 编排 & 治理 - 数据脱敏 - 可视化链路追踪 - 弹性伸缩(规划中)
三、项目状态
2、分库分表---结果归并
概念
将从各个数据节点获取的多数据结果集,组合成为一个结果集并正确的返回至请求客户端,称为结果归并。3d
咱们在实现分库分表以后,遍历
、排序
、分组
、分页
和 聚合
操做变成不在一张表上进行SQL,而是多张表执行的结果进行归并。
因此咱们来看下ShardingSphere实现这些操做的原理。
一、遍历归并
它是最为简单的归并方式。 只需将多个数据结果集合并为一个单向链表
便可。在遍历完成链表中当前数据结果集以后,将链表元素后移一位,继续遍历下一个数据结果集便可。
二、排序归并
因为在SQL中存在ORDER BY
语句,每一个数据结果集自身是有序的,因此咱们要作的就是对多个有序的数组进行排序
ShardingSphere在对排序的查询进行归并时,将每一个结果集的当前数据值进行比较(经过实现Java的Comparable接口完成),并将其放入优先级队列
。
每次获取下一条数据时,只需将队列顶端结果集的游标下移,并根据新游标从新进入优先级排序队列找到本身的位置便可。
举例
下图是一个经过分数进行排序的示例图。 图中展现了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)返回至查询客户端,而且将游标下移一位(90)以后,从新放入优先级队列。根据当前数值,t_score_0排列在队列的最后一位。 以前队列中
排名第二的t_score_2的数据结果集则自动排在了队列首位。
在进行第二次next时,只须要将目前排列在队列首位的t_score_2弹出队列,而且将其数据结果集游标指向的值返回至客户端,并下移游标,继续加入队列排队,以此类推。
当一个结果集中已经没有数据了,则无需再次加入队列。
能够看到,ShardingSphere的排序归并,是在维护数据结果集的纵轴和横轴这两个维度的有序性。
纵轴
是指每一个数据结果集自己,它是自然有序的,它经过包含ORDER BY
的SQL所获取。
横轴
是指每一个数据结果集当前游标所指向的值,它须要经过优先级队列
来维护其正确顺序。 每一次数据结果集当前游标的下移都须要将该数据结果集从新放入优先级队列排序,
而只有排列在队列首位的数据结果集才可能发生游标下移的操做。
3 、分组归并
分组归并的状况最为复杂,它分为流式分组归并
和内存分组归并
。 流式分组归并要求SQL的排序项与分组项的字段以及排序类型(ASC或DESC)必须保持一致,不然只能
经过内存归并才能保证其数据的正确性。
举例
假设根据科目分片,表结构中包含考生的姓名(为了简单起见,不考虑重名的状况)和分数。经过SQL获取每位考生的总分,可经过以下SQL:
SELECT name, SUM(score) FROM t_score GROUP BY name ORDER BY name;
在分组项与排序项彻底一致的状况下,取得的数据是连续的,分组所需的数据全数存在于各个数据结果集的当前游标所指向的数据值,所以能够采用流式归并。以下图所示
进行归并时,逻辑与排序归并相似。 下图展示了进行next调用的时候,流式分组归并是如何进行的。
经过图中咱们能够看到,当进行第一次next调用时,排在队列首位的t_score_java将会被弹出队列,而且将分组值同为“Jetty”的其余结果集中的数据一同弹出队列。 在获取了
全部的姓名为“Jetty”的同窗的分数以后,进行累加操做,那么,在第一次next调用结束后,取出的结果集是“Jetty”的分数总和。 与此同时,全部的数据结果集中的游标都将
下移至数据值“Jetty”的下一个不一样的数据值,而且根据数据结果集当前游标指向的值进行重排序。 所以,包含名字顺着第二位的“John”的相关数据结果集则排在的队列的前列。
流式分组归并与排序归并的区别仅仅在于两点:
- 它会一次性的将多个数据结果集中的分组项相同的数据全数取出。 - 它须要根据聚合函数的类型进行聚合计算。
四、聚合归并
不管是流式分组归并仍是内存分组归并,对聚合函数的处理都是一致的。 除了分组的SQL以外,不进行分组的SQL也可使用聚合函数。 所以,聚合归并是在以前介绍的归并类
的之上追加的归并能力,即装饰者模式
。聚合函数能够归类为比较、累加和求平均值这3种类型。
比较类型的聚合函数是指MAX
和MIN
。它们须要对每个同组的结果集数据进行比较,而且直接返回其最大或最小值便可。
累加类型的聚合函数是指SUM
和COUNT
。它们须要将每个同组的结果集数据进行累加。
求平均值的聚合函数只有AVG
。它必须经过SQL改写的SUM
和COUNT
进行计算,相关内容已在SQL改写的内容中涵盖,再也不赘述。
五、分页归并
上文所述的全部归并类型均可能进行分页。 分页也是追加在其余归并类型之上的装饰器,ShardingSphere经过装饰者模式
来增长对数据结果集进行分页的能力。 分页归并负责
将无需获取的数据过滤掉。
ShardingSphere的分页功能比较容易让使用者误解,用户一般认为分页归并会占用大量内存。 在分布式的场景中,将LIMIT 10000000, 10
改写为LIMIT 0, 10000010
,
才能保证其数据的正确性。 用户很是容易产生ShardingSphere会将大量无心义的数据加载至内存中,形成内存溢出风险的错觉。 其实,经过流式归并的原理可知,会将
数据所有加载到内存中的只有内存分组归并这一种状况。 而一般来讲,进行OLAP的分组SQL,不会产生大量的结果数据,它更多的用于大量的计算,以及少许结果产出的场景。
除了内存分组归并这种状况以外,其余状况都经过流式归并获取数据结果集,所以ShardingSphere会经过结果集的next方法将无需取出的数据所有跳过,并不会将其存入内存。
但同时须要注意的是,因为排序的须要,大量的数据仍然须要传输到ShardingSphere的内存空间。 所以,采用LIMIT这种方式分页,并不是最佳实践
。 因为LIMIT并不能经过索引
查询数据,所以若是能够保证ID的连续性,经过ID进行分页是比较好的解决方案
,例如:
SELECT * FROM t_order WHERE id > 100000 AND id <= 100010 ORDER BY id;
或经过记录上次查询结果的最后一条记录的ID进行下一页的查询,例如:
SELECT * FROM t_order WHERE id > 10000000 LIMIT 10;
六、总结
用最后一张图来总结归并引擎的总体结构划分