春蔚专访--MaxCompute 与 Calcite 的技术和故事

摘要:2019大数据技术公开课第一季《技术人生专访》,来自阿里云计算平台事业部高级开发工程师雷春蔚向你们讲述了MaxCompute 与 Calcite 的技术和故事。 具体内容包括: 1) 什么是查询优化器;2)MaxCompute查询优化器的具体实践;3)MaxCompute后续计划;4)从校招到阿里巴巴工程师到Calcite committer,他经历了怎样的我的成长。

如下内容根据演讲视频以及PPT整理而成。css

1、查询优化器简介

你们都知道,数据库通常由三部分组成,分别是解析器、优化器和执行引擎。一个SQL进入数据库后首先须要经过解析器进行解析,生成相应的关系表达式,而后再通过优化器优化生成物理执行计划,最后由执行引擎执行。优化器是数据库的重要组成部分,它是数据库中用于把关系表达式转换成执行计划的核心组件,在很大程度上决定了一个系统的性能。假如把数据库比做人类的“身体”,优化器就是人类的“大脑”,这个大脑决定了人体系统能走多远、走多快。算法

查询优化器主要分为两种:sql

  • 基于规则的优化器(Rule Based Optimizer,简称RBO):根据优化规则将一个关系表达式转换成另一个关系表达式,同时原有表达式被放弃,通过一系列转换生成最终执行计划。事实上,RBO是一种比较落后的优化器,它只认规则,对数据不敏感;容易陷入局部优可是全局差的场景;同时受规则顺序影响而产生不一样执行计划
  • 基于代价的优化器(Cost Based Optimizer,简称CBO):根据优化规则对关系表达式进行转换,同时原有表达式也会保留,通过一系列转换后会生成多个执行计划,以后计算每一个执行计划的Cost,从中挑选Cost最小的执行计划做为最终执行计划。CBO的优势是灵活智能,它能根据数据的特色生成相应的执行计划。所以,目前各大数据库和计算引擎都倾向于使用CBO,例如从Oracle 10g开始,Oracle已经完全放弃RBO,转而使用CBO,而Hive在0.14版本中也引入了CBO。MaxCompute 也经历了从RBO到CBO的过程,这也是MaxCompute 1.0到2.0过程当中一个重大的改变。

CBO主要有两种不一样风格的框架,一种是System-R风格,另外一种是Volcano/Cascade风格。数据库

  • System-R:sql statement通过Parser和Resolver后,首先进行查询改写,再经过优化器经过动态规划算法生成最后的物理执行计划,最后交由执行器执行。这种风格的CBO最先由IBM的数据库使用,以后被Oracle和PostgreSQL使用。
  • Volcano/Cascade:Volcano/Cascade与System-R 的不一样点在于,前者的物理优化器是Top-down,然后者是Bottom-up。Volcano/Cascade基于必定的规则体系(逻辑规则+物理规则)来生成比较好的物理执行计划。这种风格目前被SQL Server、Apache Calcite和Pivotal所使用。

Apache Calcite 是一个独立于存储与执行的SQL优化引擎,目前普遍应用于开源大数据计算引擎中,如 Flink、Drill、Kylin等。Calcite的目标是“一种方案适用于全部需求场景”,旨在为不一样的计算平台和数据源提供统一的查询引擎。如上图所示,Calcite的架构不包括存储和执行。总体流程是一个SQL statement经过JDBC Client进入JDBC Server后,通过SQL Parser 和Validator后生成关系代数表达式(Operator Expressions)。除此以外,用户还可使用Expressions Builder生成SQL的关系代数表达式,这适用于有本身特定语法的系统。生成的关系代数表达式会进入查询优化器核心引擎(Query Optimizer),负责执行动态规划算法和Cost计算。Calcite还提供一些可插拔的功能,如Metadata Providers(为优化引擎提供Metadata)和Pluggable Rules(支持用户自定义优化规则)。缓存

Calcite 主要提供了两种优化器的实现:架构

  • HepPlanner:它指的是前面提到的RBO的实现,它是一个启发式的优化器,按照规则进行匹配,直到达到次数限制(预先设置的match次数限制)或者遍历一遍后再也不出现 rule match的状况才算完成;
  • VolcanoPlanner:它指的是前面提到的 CBO 的实现,它会一直迭代 rules,直到找到 cost 最小的计划。

2、MaxCompute查询优化器实践

MaxCompute SQL优化器的整体框架以下图所示,主要包括五部分:
框架

  • 代价模型(Cost Model):用于计算Cost来选择最优的执行计划。一个好的代价模型可能会影响整个系统的性能。代价模型是一个五元组,包括CPU、IO、Row Count、Memory、Network。每一个operator只关注于自身的Cost,整个执行计划的Cost由引擎累积获得。代价模型力求可以反映客观的物理实现,如具体的IO、Network值,但不须要获得和真实如出一辙的数据,只须要可以保证选出较优的执行计划便可。
  • 优化规则:不一样的系统有不一样的优化规则,如分区裁剪规则等。
  • 统计信息:该部分对于优化器来说很是重要,缺少或很差的统计信息可能会致使生成的执行计划效果比较差。
  • 查询优化引擎:使用的是Calcite,实现了分区裁剪、链接顺序的旋转以及实现算法(如动态规划算法)的选择。
  • 基于历史的资源分配优化: 执行器执行完任务后,会将执行结果反馈给该模块,由该模块进行资源分配优化。

MaxCompute SQL优化器基于上述优化引擎实现了Shuffle Removal的功能。Shuffle指的是数据从上游任务(Task)到下游任务(Task)被处理的过程,包括分片、排序等。若是上游任务的数据已经包含了相应的物理属性,则不必进行shuffle处理。ide

举个例子,假如须要统计在2018年后建立的部门其中30岁以上员工的平均年龄,使用MaxcCompute能够获得如上图所示的物理执行计划。首先从员工表emp中过滤出30岁以上的员工,而后从部门表dept中过滤出2018年以后建立的部门,再进行join操做。考虑到数据量可能会比较大,选用Merge join进行操做。因为须要保证数据分发到同一台机器上,所以从上游Filter到Merge join须要Shuffle的处理过程(图中的EX)。此外,join以后的数据须要进行aggregate聚合操做(图中的Agg)来计算平均年龄,也须要进行Shuffle。事实上,由于以前使用的是Merge join,该过程已经作了数据的分布和排序工做,因此从join到aggregate的过程当中Shuffle就再也不须要重复去作。面对这类重复的Shuffle过程,能够经过Shuffle Removal功能去掉。函数

Shuffle Removal功能的实现依靠的是Enforcer Rule, 具体流程以下图所示。操做符如join,aggregate等要求Input数据必须具有物理数据属性Trait(经过排序、分片等操做得到),Enforcer Rule能够保证Input数据所须要的物理属性(Required Trait):1) 若Input数据不具有Required Trait,则须要增长Shuffle过程;2)若Input数据自己已经知足Required Trait,则无需添加;3)Input能够进行特性传递,即将Required Trait下推到本身的Input中。Shuffle Removal功能上线后已经为阿里云带来了大约10%的资源节省。性能

3、Maxcompute SQL新功能介绍

MaxCompute在阿里巴巴承接了99%的计算和存储,同时也关注提升外部用户的用户体验和计算效率。接下来要介绍的是MaxCompute 2.0的新功能,主要包括编译器、开发利器Studio、帮助提高开发效率的过程化支持功能(如脚本模式、参数化视图)以及自定义功能(如UDT、外表)。在这里须要提到的是,因为公共云还没有正式发布,如需使用,可搜索钉钉群号11782920,联系群主晋恒进行使用。

编译器

MaxCompute 2.0中编译器目前有三个主要的新功能:1)全部的编译错误包含行列号信息,从而帮助用户清晰地了解错误的位置;2)同义词编译中的多个错误会经过错误报告的形式一次性报出来,方便用户进行修改;3)支持warning,提示用户潜在的问题,如Double = STRING精度受损,该功能须要经过set odps.compiler.warning.disable=false预先打开。以上三个功能在开发中很是实用,将极大提升用户的开发效率。

Studio

第二个须要强烈推荐的是Maxcompute 2.0的Studio。做为一款IDE,用户能够经过它来编写脚本,其好处主要包括如下几点(以下图所示):

1)做业监控:提供详细而直观的做业流程图,用户能够方便地查看任务流程以及总体的执行计划(左上角子图);
2)做业分析:提供与做业分析相关的数据信息(左下角子图),如每个任务中Operator的执行时间,经过这些信息,用户能够很直观地看到那部分计划执行得很差,哪部分的资源占用比较高、执行时间比较长,从而进行定向调优,有的放矢地提高执行计划的效率;
3)实时提示SQL中的错误,而且能够一次性提示全部错误和警告,提示用户写的SQL哪里有问题(右上角子图);
4)智能提示:根据用户输入的部分字母以及上下文判断并提示用户可能要输入的命令,帮助用户方便地自动补齐代码(右下角子图)。

脚本模式

问题场景:当面临处理逻辑很复杂的项目时,须要提取多个表后对这些表进行join操做,而后再对结果进行join操做。此外还须要从不一样的运行阶段输出多个表,即便使用CTE(Common Table Exclusion)也没法表达,这种状况下只能将这些步骤拆分为多个做业顺序提交。这种解决方案的复杂度和维护成本都比较高,同时给性能带来很大影响。

脚本模式解决方案:针对这种需求,MaxCompute 2.0提供了脚本模式的功能。仍是之前面提到的例子(统计在2018年后建立的部门中30岁以上员工的平均年龄)来介绍脚本模式的使用,经过MaxCompute的脚本模式,全部命令能够写在一个SQL文件中,用户首先能够定义一个变量a,从员工表emp中筛选年龄大于30岁的员工列表;而后定义一个变量b,从部门表dept中筛选建立时间在2018-01-01以后的部门列表;其次定义一个变量c,统计这些部门中30岁以上员工的平均年龄。所获得的结果能够经过脚本模式很方便地进行后续处理,好比直接经过多个脚本命令将所需的结果插入到不一样的表中(具体命令以下图所示)。在面对很是复杂的查询时,使用这种方式使得查询操做和后续的操做更加易于维护、更加清晰。

脚本模式主要有如下三方面的优势:

  • 复杂性低:以脚本为单位提交查询,适合提交复杂的查询;
  • 易用性高:符合开发者的思考过程,适合编写复杂逻辑;
  • 性能高:充分发挥优化器能力(基于代价,脚本复杂越有优点)。

参数化视图

问题场景:假设用户作了一个视图给其余团队用,功能是读取一个数据表,运行新写的模式识别算法提供广告推荐建议。其余团队发现该用户的算法很好也想用,可是底层访问的数据表不同,一些模式识别的参数也不同,只好给他们再作一个新的视图。后来发现原来的视图有bug,只有一个个的修改,给维护带来了很大的复杂性。

参数化视图解决方案:针对这种状况,MaxCompute 2.0提供了参数化视图的方式来解决。其语法相似于建立普通的视图view,不一样点是参数化视图的建立须要用到两个参数,一个是表参数@a(自己包含两个参数k,v)和String参数@b。参数化视图的建立命令以下图所示,其中建立过程结合了脚本模式。能够发现,经过这种方式建立的视图能够很方便地给任何用户来使用,由于其模式相同,只有参数类型不一样而已。

自定义功能(UDT)

问题场景:Hive和MaxCompute中均可以写UDF来知足某些没有内建函数的需求。好比须要实现一个JSON字符串解析的功能,这个功能用其余语言实现很是简单,好比用Java可能只须要一次调用JSON函数就行了,可是MaxCompute的内置函数没有实现这一功能,为此写一个UDF复杂性过高。

UDT解决方案:针对上述问题场景,MaxCompute2.0提供了UDT(User Defined Type)功能,容许用户在SQL中直接引用第三方语言的类或者对象,获取其数据内容或者调用其方法 。对于上述问题,只须要以下SQL就能解决。这种方式避免了频繁建立UDF,能够像使用Java调用同样方便。

外表

问题场景:MaxCompute用户的数据存储在其余存储系统上,如HDFS,而且格式是CSV格式,有办法使用SQL来操做吗?

外表解决方案:MaxCompute中的外表功能支持用户使用SQL来访问其余数据源和其余数据格式的数据。下图举了一个例子,处理存储在 OSS上的CSV文件。首先须要定义一个外表,定义命令中须要指定csv读取的schema,MaxCompute内置csv文件的handler以及要处理的css的位置;外表定义好以后就能够直接对数据进行读取,抽取的数据能够直接参与SQL运算(和普通的SQL无异),无缝链接。

外表功能支持多种数据源和数据格式,同时支持用户自定义的数据格式(以下图所示)。

4、MaxCompute后续计划

在介绍MaxCompute后续计划以前,首先总结一下其相对于Hive的优点:

  • TPCH上有1倍以上的性能提高
  • SQL标准支持更好:Hive在跑TPC-DS这个benchmark的时候,有不少SQL是不支持的,而MaxCompute能够作到100%支持;
  • 更好的编译器:支持一次性报告错误,高效的错误恢复,支持warning;
  • Runtime硬基础好:基于CPP实现的runtime,能够达到更高效率
  • 更好的IDE支持:MaxCompute Studio
  • 对小做业支持更好:经过Service Mode支持,对于小做业能够作到秒级甚至毫秒级的查询;
  • 支持更多好用的语法:包括VALUES表达式、SCALAR SUBQUERIES、INTERSECT / MINUS、PYTHON UDF、UDT / UDJ、脚本模式和参数化视图。

在后续版本中,MaxCompute将主要增长两部分的新功能:

  • 内存计算:支持数据缓存在内存中,一次加载数据屡次使用,极大减小运行时间;
  • 更强大的脚本语言功能:好比支持在SQL中使用条件语句IF/ELSE,以及循环语句 LOOP。

5、我的成长经历及经验

从校招15年进入到阿里巴巴MaxCompute团队,见证了MaxCompute从1.0到2.0的发展,我的经验上来说,从学校来到阿里巴巴至关于从一个校园来到另外一个“校园”。团队自己基于开源社区项目Apache Calcite项目,同时也是其深度用户。使用过程当中,团队将一些好的想法贡献给社区,社区也积极接纳,于是成为committer是水到渠成的事情。

最先接触开源社区是在两年前,说到我的经验,总结起来主要有两点:
1)成长是按部就班的,一开始可能承担的是很小的需求实现,经过积极地和社区交流学习,按部就班,承担的需求会愈来愈大,贡献也会逐渐增多;
2)从开源社区能够学到不少东西,开源社区比较注重代码质量和社区成员之间的沟通交流,经过及时的沟通交流会提早避免不少没必要要的冲突和返工。



本文做者:晋恒

原文连接

本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索