技术分享 | 基于分布式中间件的SQL改造指南

4月12日,GOPS全球运维大会在深圳隆重召开,全球运维大会是国内第一个运维行业大会,爱可开源社区在基础架构及DevOps解决方案专场分享了《基于分布式中间件的SQL改造指南》的主题演讲。后端


本文由根据演讲内容进行整理,但愿有助于你们对分布式架构的理解及SQL改造实践。网络



 “ 如下为正文部分 ” 
架构



一.中间件中的简单SQL


1.简单SQL的分类


在通常SQL中,一个单表查询的SQL每每是最简单的,而在中间件中也没什么区别,中间件中将一个对于单表的字段查询做为最简单的SQL进行处理。app


2.中间件对于简单SQL的处理方式


下面先来简单的回顾下中间件中的表格处理的最基础方式。运维


图片


中间件会按照在配置文件中既定的数据拆分的设置,对于“用户表”这个表格的数据进行拆分,将每条经过中间件插入的数据按照规则进行分布,图上给的例子是按照“用户表”的ID奇偶性进行了数据的拆分。分布式


有了合理的数据分布以后就是中间件是如何在须要的时候取用数据,在中间件中,对于基础SQL,也就是单表的数据查询分为一下两个状况:ide


  • 带有分片信息的数据查询:下图展现了一个例子,在单表查询的过程当中,若是存在影响数据分布的查询条件(在此例子中为用户的ID=1),优化


在查询的简单SQL附带有分片条件时,中间件根据SQL语义解析的结果,根据这个分片条件对于数据可能存在的DB进行计算,最终把SQL转发到对应的DB中进行执行,查询出最终的正确结果。spa


  • 不带有分片信息的数据查询(广播):当查询的SQL不带有分片条件时,中间件只好把SQL内容发送到表格涉及到的全部DB中,并从每一个DB中返回数据并整合。3d



在这个过程当中就存在一个现象,即“这一个查询须要等待最慢的那个DB查询结束”。


3.简单SQL的注意事项


上文中有说起广播类型的简单SQL存在一个特征“须要等待最慢的那个DB查询结束”,当分片数量持续上升的时候,以下图所示的场景,须要等待的链接数量会持续变多。



能够经过几率的方法分析下当链接数量增加的时候会发生什么变化:



经过Matlab对于中间件广播查询的场景进行了以下的模拟,能够发如今随着须要等待链接数量的上升,总体的中间件响应速度会有一个成倍的降低,从单个链接平均5ms的查询延迟一直上升到100链接时候的接近15ms的总体延迟。


针对以上的场景,提出在中间件中进行单表查询的时候,尽可能下降单个SQL涉及到的后端DB数量,具体方法是在SQL中给表格添加分片列的限定条件,就像select * from 用户表 where ID = 1中的这个条件ID =1。


二.中间件中的ER表格JOIN


1.中间件中ER关系的定义


单表查询不能覆盖应用对于SQL的需求,中间件中就引入了ER关系的概念。


ER关系指的是两个表格在逻辑上就拥有的从属关系,以下图中所示的用户表和订单表:



当两个表或者更多的表格存在这样逻辑上的从属关系的时候,在中间件中把这些关系定义为ER关系,而且当一个查询语句有且仅有存在ER关系的表格关联组成的时候,这个SQL被称为“ER表格JOIN”。


2.中间件对于ER表格JOIN的处理方式


当两个表格可以被定义为ER关系的时候,中间件可以按照之间的关联关系组织数据的存储,最后的存储方式以下图所示:


图片


能够看到大体的结果就是子表(订单表)的数据会被存放在父表(用户表)对应数据的DB节点。


当出现这种数据分布的时候,就能够在DB1中查询到上例中张三的用户和他的全部数据,因此中间件就能直接把SQL语句下发到对应节点进行执行。


3.ER关联SQL的注意事项


能够看到ER的这种查询方式是有必定的局限的,须要把查询的表格声明为ER关系,而且ER关系仍是单向的,就是一个表只能是某一个表的子表,一个分片表不能拥有两个父表。


其次就是因为这个ER关联的查询处理是和上文的简单查询在本质上是同样的,就是查询SQL下发到DB中来执行,因此在注意事项上也是一致的,尽可能在使用的时候提供可以肯定分片的限定条件。


三.中间件中的跨库表格JOIN


1.跨库表格JOIN的定义


事实上上文全部的查询方法限制都是很是大的,可是每每应用的SQL没法知足于被限制在这么局限的范围内,那中间件中就有另外一种机制来实现更普遍意义上的SQL执行,跨库表格关联查询。


当个人SQL内容没法被定义进入上文的两个“简单SQL”或者是“ER SQL”的时候,中间件就会使用这种跨库表格JOIN的方式来处理这个问题,固然并不是全部的中间件都有实现对应的功能,在这里仅讨论实现的部分中间件的实现逻辑。


2.中间件中跨库表格JOIN的执行


如下是在中间件中执行跨库表查询的这么一个大体执行逻辑图,图中能够看到总体的执行逻辑是从每一个DB中分别取TABLEA和TABLEB的数据,最终在中间件中进行数据的整理组织和对比:


图片


具体的跨库查询的执行过程能够被概括为如下的几个步骤:

  • 根据配置文件中对于TABLEA和TABLEB的描述将表格的数据分别从DB中进行查询

  • 对于查询获得的表格数据进行整理,分别按照ID的值(关联列的值)进行排序和归档

  • 对于归档完成的数据进行ID值的对比,计算关联结果


在这个过程当中会产生几个方面的资源消耗:

  • 组织数据产生的临时内存存储消耗

  • 对比数据产生的CPU消耗

  • 查询每个存在DB中的表数据产生的链接数以及网络消耗


另外一个方面就是中间件因为不能存储真实的数据,因此没法像MySQL优化器同样提早计算不一样表格的聚合代价,这么一来,中间件就直接按照SQL中原有的表格聚合顺序进行数据的聚合和整理,这可能带来如下的SQL执行的计划。


图片


案例中用户表因为表格顺序的问题先和没有直接关系的商品表进行了表关联,这样一来这里的中间结果就出现了一个笛卡尔积,也就是无条件无字段的关联结果,其结果为双边数据的乘积:


1000X1000=1000000


若是SQL中的表格顺序进行进一步的优化,则能够在一样的SQL中得到如下图中的执行顺序。


图片


此次咱们优化完成以后的查询中间结果将由用户表和有关系的订单表优先聚合完成,由于他们之间的关系,最多存在2000条中间结果,相比与上例中的1000000条来讲,整个SQL执行效率上获得了很大的优化


3.跨库JOIN的注意事项


针对以上的几种消耗类型,能够经过如下的几个手段进行下降消耗的量以获取最好的执行效果:

  • 添加足够的限定条件

  • 使用重复率低的列进行关联

  • 经过手动调整SQL中表格顺序的手段来进行执行计划的调整


四.通篇总结


从DB存储到真正成熟的分布式DB,分布式中间件的架构是整个过程当中的重要一环,在分布式架构的过程当中,对SQL的规范和使用存在一些特别要求,应用在向这方面进行改造和适应的过程当中须要更多的考虑到中间件架构带来的限制及相关注意事项。总体概括可分为如下内容:


1.在中间件中尽可能使用分片条件进行数据的查询,不论整个SQL是属于简单SQL,ER查询或者是复杂查询。

2.在复杂查询的状态下,优化方向为中间件中处理的数据尽可能少,此目标能够经过给表格添加限定条件,选择更加剧复率低的关联列以及调整SQL中的表格关联顺序来达成。

相关文章
相关标签/搜索