文章目录
- SparkSQL运行架构及原理
- 1.1. Catalyst优化器简介
- 1.2. SparkSQL运行架构
- 1.3. SparkSQL解析Core底层原理
- 1.4. 执行计划查看
SparkSQL运行架构及原理
1.1. Catalyst优化器简介
SparkSQL使得我们开发人员可以使用DSL风格的数据来处理数据,甚至可以直接使用SQL风格的代码来处理数据。而无论是使用的DSL风格还是SQL风格,在底层的时候其实都是将SQL解析成为SparkCore的程序(RDD)提交到集群上去运行的。但是与直接编写SparkCore的程序不同:
- 在SparkCore部分,我们使用到RDD作为编程模型,程序执行的时候会严格按照开发人员编写的代码逻辑来执行。如果代码的质量比较低的情况下,程序的执行效率也会受到影响。
- SparkSQL程序则不同,SparkSQL会自动的将代码(DSL、SQL)进行优化,以提高代码的执行效率,最终将优化后生成的RDD的程序提交到Spark去执行。避免开发人员可能因为能力的不足而导致程序的执行效率低下。
在这里就有一个非常重要的组件存在了:Catalyst优化器,SparkSQL可以将代码自动优化,就是靠它来完成的!
SparkSQL的前身是Shark,最开始的时候底层代码优化、SQL的解析、执行引擎等等完全基于Hive,总是Shark的执行速度要比Hive高出一个数量级,但是Hive的发展制约了Shark。因此在15年中旬的时候,Shark的负责人将Shark项目结束掉,重新独立出来的一个项目,就是SparkSQL。SparkSQL使用了新的优化器替代Hive的优化器,这个新的优化器就是Catalyst。
1.2. SparkSQL运行架构
- 开发人员开发SparkSQL程序,可以使用DSL风格或者SQL风格。
- 将程序提交给Catalyst,Catalyst会对SQL进行解析,生成执行计划。
- Catalyst最终将SparkSQL的程序进行解析、优化之后,生成的SparkCore的程序。
- 将最终的代码提交到Spark集群运行。
1.3. SparkSQL解析Core底层原理
SparkSQL对SQL语句的处理与关系型数据库类似,即**词法/语法解析、绑定、优化、执行。**SparkSQL会先将SQL语句解析成一棵树,然后使用规则对Tree进行绑定、优化等处理过程。
-
使用SessionCatalog保存元数据
在解析SQL语句之前,会创建SparkSession对象(在Spark2.0的版本之前是SQLContext对象),SparkContext只是封装了SparkContext和SQLContext的创建而已,并不会有元数据信息。元数据是保存在SessionCatalog中的,包括表名、字段名称、字段类型等。创建临时表或者视图的时候,其实也是向SessionCatalog注册的。
-
解析SQL,使用ANTLR生成未绑定的逻辑计划
当调用SparkSession的SQL或者SparkContext的SQL方法的时候,就会使用SparkSQLParser进行SQL的解析,使用的是ANTLR进行词法解析和语法解析。它分为两个步骤来生成未解析的逻辑计划(Unresolved LogicalPlan)
- 词法解析:Lexical Analysis,负责将Token分组成符号类
- 构建一个分析书或者语法树AST
-
使用分析器Analyzer绑定逻辑计划
在这个阶段,Analyzer会使用Analyzer Rules,并结合SessionCatalog,对未绑定的逻辑计划进行解析,生成已绑定的逻辑计划。
-
使用优化器Optimizer优化逻辑计划
在这个阶段,优化器也是会定义一套Rules,利用这些Rule对逻辑计划和Expression进行迭代处理,从而使得树的节点进行合并和优化。
-
使用SparkPlanner生成物理计划
SparkPlanner使用PlanningStrategies,对优化后的逻辑计划进行转换,生成可以执行的物理计划SparkPlan。
-
使用QueryExecution执行物理计划
此时调用SparkPlan的execute方法,底层其实已经在触发Job了,然后返回RDD。
1.4. 执行计划查看
from pyspark.sql import SparkSessionwith SparkSession.builder.master("local[*]").appName("p").enableHiveSupport().getOrCreate() as spark:spark.sql("""select ename, dname from mydb.emp join mydb.dept on mydb.emp.deptno = mydb.dept.deptno where comm is not null """).explain(True)