SparkSQL运行架构及原理

文章目录

      • SparkSQL运行架构及原理
          • [1.1. Catalyst优化器简介](#1.1. Catalyst优化器简介)
          • [1.2. SparkSQL运行架构](#1.2. SparkSQL运行架构)
          • [1.3. SparkSQL解析Core底层原理](#1.3. SparkSQL解析Core底层原理)
          • [1.4. 执行计划查看](#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运行架构
  1. 开发人员开发SparkSQL程序,可以使用DSL风格或者SQL风格。
  2. 将程序提交给Catalyst,Catalyst会对SQL进行解析,生成执行计划。
  3. Catalyst最终将SparkSQL的程序进行解析、优化之后,生成的SparkCore的程序。
  4. 将最终的代码提交到Spark集群运行。
1.3. SparkSQL解析Core底层原理

SparkSQL对SQL语句的处理与关系型数据库类似,即**词法/语法解析、绑定、优化、执行。**SparkSQL会先将SQL语句解析成一棵树,然后使用规则对Tree进行绑定、优化等处理过程。

  1. 使用SessionCatalog保存元数据

    在解析SQL语句之前,会创建SparkSession对象(在Spark2.0的版本之前是SQLContext对象),SparkContext只是封装了SparkContext和SQLContext的创建而已,并不会有元数据信息。元数据是保存在SessionCatalog中的,包括表名、字段名称、字段类型等。创建临时表或者视图的时候,其实也是向SessionCatalog注册的。

  2. 解析SQL,使用ANTLR生成未绑定的逻辑计划

    当调用SparkSession的SQL或者SparkContext的SQL方法的时候,就会使用SparkSQLParser进行SQL的解析,使用的是ANTLR进行词法解析和语法解析。它分为两个步骤来生成未解析的逻辑计划(Unresolved LogicalPlan)

    • 词法解析:Lexical Analysis,负责将Token分组成符号类
    • 构建一个分析书或者语法树AST
  3. 使用分析器Analyzer绑定逻辑计划

    在这个阶段,Analyzer会使用Analyzer Rules,并结合SessionCatalog,对未绑定的逻辑计划进行解析,生成已绑定的逻辑计划。

  4. 使用优化器Optimizer优化逻辑计划

    在这个阶段,优化器也是会定义一套Rules,利用这些Rule对逻辑计划和Expression进行迭代处理,从而使得树的节点进行合并和优化。

  5. 使用SparkPlanner生成物理计划

    SparkPlanner使用PlanningStrategies,对优化后的逻辑计划进行转换,生成可以执行的物理计划SparkPlan。

  6. 使用QueryExecution执行物理计划

    此时调用SparkPlan的execute方法,底层其实已经在触发Job了,然后返回RDD。

1.4. 执行计划查看
python 复制代码
from pyspark.sql import SparkSession

with 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)