文档章节

Sharding-Sphere自动化执行引擎

xiaomin0322
 xiaomin0322
发布于 09/25 11:52
字数 3862
阅读 14
收藏 4

Q: 什么叫"自动化执行引擎"?

 

A: 一条SQL的生命周期是:从客户端发起、经过Sharding-Sphere处理、再到底层数据库执行消化。而在Sharding-Sphere里过程则是:SQL解析-->SQL优化-->SQL路由-->SQL改写-->SQL执行-->结果归并。自动化执行引擎是为了处理SQL执行问题的,即将路由改写后的真实SQL如何有控制且高效地传送到底层数据库执行。那么直接通过JDBC发送SQL至数据库执行难道行不通吗?还有其他需要考虑吗?答案是:肯定有其他考虑,否则我就不用写这篇文章了。这就体现在它的"自动化"上了。所谓"自动化",其实是为了平衡数据库连接创建与结果归并模式选择问题,为了平衡资源控制与执行效率问题。

 

 

需求场景

 

Q: 为何需要自动化执行引擎呢?

 

A: 在概念介绍部分,我们介绍了主角-自动化执行引擎。也谈到它的自动化是为了平衡数据库连接创建以及结果归并模式选择问题。这是它诞生的宿命,历史的选择。下面将为大家介绍这两个需要平衡的问题:

 

1. 数据库连接创建

作为一位混娱乐圈的DBA出身的Java coder, 多少还是会从DBA角度考虑问题。比如从资源控制的角度看,业务方访问数据库的连接数量应当有所限制,这能够有效地防止某一业务操作过多地占用资源,从而将数据库连接的资源耗尽,以致于影响其他业务的正常访问。特别是在一个数据库实例中存在较多分表的情况下,一条不包含分片键的逻辑SQL将产生落在同库不同表的大量真实SQL,如果每条真实SQL都占用一个独立的连接,那么一次查询肯定将会占用过多的资源。Sharding-Sphere作为数据库中间层,如果没有控制好数据库连接数量而导致连接暴增、数据库压力过大的话,极有可能被强行背锅。

 

2. 结果归并模式选择

但是从执行效率的角度看,为每个分片查询维持一个独立的数据库连接,可以更加有效地利用多线程来提升执行效率。为每个数据库连接开启独立的线程,可以并行化IO所产生的消耗。独立的数据库连接,能够保持查询结果集的引用以及游标位置,在需要获取相应数据时移动游标即可,避免了过早将查询结果数据加载至内存。这就涉及到了结果归并模式的选择问题。通过上一篇文章《剖析Sharding-Sphere系列——结果归并》介绍,我们知道当前有两种结果归并的模式,分别是:

 

流式归并:以结果集游标下移进行结果归并的方式,称之为流式归并,它无需将结果数据全数加载至内存,可以有效地节省内存资源,进而减少垃圾回收的频次。

 

内存归并:以读取内存中加载的结果集进行归并的方式,进行数据对比归并。它需要将结果数据全数加载至内存。

 

相信只要是智商在线的朋友,一定会选择流式归并来处理结果集。可是,如果无法保证每个分片查询持有一个独立数据库连接的话,那么就需要在复用该数据库连接、获取下一张分表的查询结果集之前,将当前的查询结果集全数加载至内存。因此,即使可以采用流式归并,在此场景下也不得不退化为内存归并。

 

一方面是对数据库连接资源的控制保护,一方面是采用更优的归并模式达到内存资源节省的目的,如何处理好两者之间的关系,是Sharding-Sphere执行引擎需求解决的问题。具体来说,如果一条SQL在经过Sharding-Sphere的分片后,需要操作某数据库实例下的200张表,那么,是选择创建200个连接并行执行,还是选择创建一个连接串行执行呢?效率与资源控制又应该如何抉择呢?

 

 

进化论

 

针对上述的场景,Sharding-Sphere在3.0.0.M4之前提供了一种解决思路,即提出了连接模式(Connection Mode)的概念,并划分了两种模式:内存限制模式(MEMORY_STRICTLY)和连接限制模式(CONNECTION_STRICTLY)这两种类型。

  • 内存限制模式

    使用此模式的前提是数据库对其一次操作所耗费的连接数量不做限制。如果实际执行的SQL需要对某数据库实例中的200张表做操作,则对每张表创建一个新的数据库连接,并通过多线程的方式并发处理,以达成执行效率最大化。并且在SQL满足条件情况下,优先选择流式归并,以防止出现内存溢出或避免频繁垃圾回收情况。

 

  • 连接限制模式

    使用此模式的前提是数据库严格控制对其一次操作所耗费的连接数量。如果实际执行的SQL需要对某数据库实例中的200张表做操作,那么只会创建唯一的数据库连接,并对其200张表串行处理。如果分片在不同的数据库,仍然是多线程处理不同库,但每个库的每次操作仍然只创建一个唯一的数据库连接。这样即可以防止对一次请求对数据库连接占用过多所带来的问题。该模式始终选择内存归并。

 

内存限制模式适用于OLAP操作,可以通过放宽对数据库连接的限制提升系统吞吐量;连接限制模式适用于OLTP操作,OLTP通常带有分片键,会路由到单一的分片,因此严格控制数据库连接,以保证在线系统数据库资源能够被更多的应用所使用,是明智的选择。

 

而Sharding-Sphere最终使用何种模式的决定权就交由用户。Sharding-Sphere提供对连接模式的配置,让开发者依据自己业务的实际场景需求选择使用内存限制模式或连接限制模式。

 

可是,将两难的选择的决定权甩锅给用户,使得用户必须要了解这两种模式的利弊,并依据业务场景需求进行选择。这显然增加了用户对Sharding-Sphere的学习和使用的成本,这并不是一种最优的解决方案。

 

此外,这种一分为二的处理方案,将两种模式的切换交由静态的初始化配置,缺乏灵活应性。在实际的使用场景中,面对不同SQL以及占位符参数,每次的路由结果是不同的。这就意味着某些操作可能需要使用内存归并,而某些操作则可能选择流式归并更优,它们不应该由用户在Sharding-Sphere启动之前配置好,而更应该根据SQL和占位符参数的场景,来动态的决定连接模式。

 

像Sharding-Sphere这样,总是站在用户角度考虑问题并且不断优化精进的七道杠青年是一定要进行相关优化调整的,于是自动化执行引擎就进化出来了。

 

为了降低用户的使用成本以及连接模式动态化这两个问题,Sharding-Sphere提炼出自动化执行引擎的思路,在其内部消化了连接模式的概念。用户无需了解所谓的内存限制模式和连接限制模式是什么,而是交由执行引擎根据当前场景自动选择最优的执行方案。

 

同时,自动化执行引擎将连接模式的选择粒度细化至每一次SQL的操作。针对每次SQL请求,自动化执行引擎都将根据其路由结果,进行实时的演算和权衡,并自主地采用恰当的连接模式执行,以达到资源控制和效率的最优平衡。针对自动化的执行引擎,用户只需配置maxConnectionSizePerQuery即可,该参数表示一次查询时每个数据库所允许使用的最大连接数,剩余的处理逻辑将由自动化执行引擎为您负责。

 

 

实现解析

 

整个自动化执行引擎的执行流程如下图所示。

 

在路由改写完成后,我们会得到路由结果(SQLRouteResult),这个结果集主要包含了SQL、SQL的参数集、数据库等信息。其数据结构如下图所示:

执行引擎的执行过程分为准备、执行两个阶段。

 

  • 准备阶段

顾名思义,此阶段用于准备执行的数据。它分为结果集分组和执行单元创建两个步骤。

 

   a. 结果集分组

该步骤是实现内化连接模式概念的关键。执行引擎根据maxConnectionSizePerQuery配置项,结合当前路由结果,自动选择恰当的连接模式。具体步骤如下:

 

1. 将SQL的路由结果按照数据库的名称进行分组。

2. 通过下图的公式获得每个数据库实例在maxConnectionSizePerQuery的允许范围内,每个数据库连接需要执行的SQL路由结果组,并演算出本次请求最优的连接模式。

 

 

在maxConnectionSizePerQuery允许的范围内,当一个连接需要执行的请求数量大于1时,意味着当前的数据库连接无法持有相应的数据结果集,则必须采用内存归并;反之,当一个连接需要执行的请求数量等于1时,意味着当前的数据库连接可以持有相应的数据结果集,则可以采用流式归并。

 

每一次的连接模式的选择,是针对每一个物理数据库的。也就是说,在同一次查询中,如果路由至一个以上的数据库,每个数据库的连接模式不一定一样,它们可能是混合存在的形态。

 

   b. 执行单元创建

该步骤通过上一步骤获得的路由分组结果创建用于执行的单元。执行单元是指为每个路由分组结果创建相应的数据库连接。

 

当数据库被限制了连接资源数量且线上业务出现大量并发操作时,如果不妥善处理并发获取数据库连接的问题,则很有可能会发送死锁。在多个请求相互等待对方释放数据库连接资源时,就会产生饥饿等待,造成交叉死锁。

 

举个栗子,假设一次查询需要在某一数据库上获取2个数据库连接,用于路由至一库的2个分表查询。有可能出现查询A已获取到该数据库的1个数据库连接,并等待获取另一个数据库连接;而查询B则也已经获得了该数据库上的1个数据库连接,并同样等待另一个数据库连接的获取。如果数据库连接池的允许最大连接数是2,那么这2个查询请求将永远孤独地等待着彼此,图绘版的解释可能会更便于大家理解:

为了避免死锁的出现,Sharding-Sphere在获取数据库连接时进行了同步处理。它在创建执行单元时,以原子性的方式一次性获取本次SQL请求所需的全部数据库连接,杜绝了每次查询请求获取到部分资源的可能。这种加锁做法确实可以解决死锁问题,只是,同时会带来一定程度并发性能的损失。为了展示我们不一样!有啥不一样呢?

我们针对此问题还进行了以下两方面优化:

 

1.    避免锁定一次性只需获取一个数据库连接的操作。因为每次仅需要获取一个连接,就不会发生两个请求相互等待的场景,无需锁定。对于大部分OLTP的操作,都是使用分片键路由至唯一的数据节点,此时无需担心交叉死锁问题,也无需考虑加锁问题,从而减少对并发效率的影响。除了路由至单分片的情况,读写分离也属于此范畴之内的场景。

2.    仅针对内存限制模式进行链接资源的锁定。在使用连接限制模式时,数据库连接资源在所有查询结果集装载至内存之后被释放掉,因此不必考虑死锁等待、加锁处理的问题。

 

  • 执行阶段



  •  

该阶段用于真正的执行SQL,它分为分组执行和归并结果集生成两个步骤。

   a. 分组执行

该步骤将准备执行阶段生成的执行单元分组下发至底层并发执行引擎,并针对执行过程中的每个关键步骤发送事件。如:执行开始事件、执行成功事件以及执行失败事件。执行引擎仅关注事件的发送,它并不关心事件的订阅者。Sharding-Sphere的其他模块,如:分布式事务、调用链路追踪等,会订阅感兴趣的事件,并进行相应的处理。

   b. 归并结果集生成

Sharding-Sphere通过在执行准备阶段的获取的连接模式,生成内存归并结果集或流式归并结果集,并将其传递至结果归并引擎,以进行下一步的工作。内存归并结果集或流式归并结果集的核心区别是:流式归并结果集会通过游标方式获取结果集的数据,而内存归并结果集则是从内存里获取数据。这也是内存归并和流式归并的数据基础。

 

通过上述所有步骤就完成了自动化执行引擎的执行流程。其核心目的是自动化平衡数据库连接创建以及结果归并模式选择问题,实现细粒度地平衡把控每一次查询的资源控制与执行效率,从而减少用户的使用学习成本和业务场景变化的担忧。

本文转载自:https://mp.weixin.qq.com/s/hIKZPJDfGfeduW4frwVN_w

共有 人打赏支持
xiaomin0322
粉丝 108
博文 3550
码字总数 165463
作品 0
上海
架构师
sharding-sphere之sql执行那些事

以官方例子如下,调试sharding-sphere代码: 可以看到,首先获取数据源连接池,然后执行drop语句,创建表,插入数据,再修改。在获取数据源的时候,实质初始化的是sharding-sphere的数据源。...

一滴水的坚持
07/09
0
0
Sharding-Sphere 3.0.0.M4 正式发布

Sharding-Sphere 3.0.0.M4 正式发布了,Sharding-Sphere 是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(规划中)这3款相互独...

h4cd
09/29
0
0
分布式事务在Sharding-Sphere中的实现

本文根据dbaplus社群第156期线上分享整理而成。 一切从ACID开始说起。ACID是本地事务所具有的四大特征: Atomicity:原子性 事务作为整体来执行,要么全部执行,要么全不执行。 Consistency:...

赵俊
08/01
0
0
分布式事务在Sharding-Sphere中的实现(有彩蛋)

本文根据dbaplus社群第156期线上分享整理而成,文末还有好书送哦~ 一切从ACID开始说起。ACID是本地事务所具有的四大特征: Atomicity:原子性 事务作为整体来执行,要么全部执行,要么全不执...

DBAplus社群
08/01
0
0
集成 Proxy 与 DB Mesh,Sharding-JDBC 3 将"Sharding"做到极致

嘉宾:张亮 作者:h4cd 提起数据库中间件,我们可以很自然地联想到 OneProxy、TDSQL、Sharding-JDBC 与 MyCat 等知名项目。在众多的数据库中间件实现技术中,通常存在两种架构模式,一种是 ...

编辑部的故事
05/23
0
19

没有更多内容

加载失败,请刷新页面

加载更多

关于Jackson默认丢失Bigdecimal精度问题分析

问题描述 最近在使用一个内部的RPC框架时,发现如果使用Object类型,实际类型为BigDecimal的时候,作为传输对象的时候,会出现丢失精度的问题;比如在序列化前为金额1.00,反序列化之后为1.0...

ksfzhaohui
18分钟前
0
0
vue less安装

$ npm install less less-loader --save 安装成功后修改文件:build>webpack.base.conf.js 在model.rules添加对象: { test: /\.less$/, loader: "style-loader!css-loader!less-loade......

shawnDream
23分钟前
0
0
kolla-ansible部署容器ceph

kolla是从openstack孵化出的一个项目,kolla项目可以制作镜像包括openstack、ceph等容器镜像, ansible是自动化部署工具,执行playbook中的任务。 kolla-ansible是容器部署工具,部署opensta...

zrz11
28分钟前
0
0
【三 异步HTTP编程】 1. 处理异步results

异步results 事实上整个Play框架都是异步的。Play非阻塞地处理每个request请求。 默认的配置适配的正是异步的controller。因此开发者应该尽力避免在在controller中阻塞,如在controller方法中...

Landas
30分钟前
0
0
Android Studio 3.1.4 buildApk遇到问题 Connection reset

打开设置,找到Android Studio选项卡,把下图选项打上勾就ok

lanyu96
31分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部