你真的懂SparkSQL原理吗Spar
我先让他说了下SparkSQL的原理。他肯定做好了功课:SparkSQL原理=逻辑执行计划+解析后的逻辑执行计划+优化后的逻辑执行计划+物理执行计划。脸上逐渐漏出了得意的笑容,于是,我连续发问:
SparkSQL解析执行计划时是如何遍历语法树的?大家都说不推荐用RDD,应该用DataFrame,你从底层实现上说说为什么?SparkSQL用RDD了吗?它是怎么用的?你前面说的是一个非常基础,宽泛的流程,我想听的是Spark物理执行计划的生成细节?SparkSQL中的CodeGenerate过程底层是如何实现的?Optimizer优化器和Analyzer处理模式一样吗?怎么处理的?中间他不断地想把我扯到其他领域,说着模棱两口的回答。不断地解释他们公司的业务是如何如何,平台是如何如何。但作为一名常年面试的面试官,怎么可能让他带偏呢。整个过程就是,我挖一个坑,他马上就跳进去,然后自己再也出不来了。我再拉他出来,然后他自己又跳进去了。其实,说到底,他并不熟悉源码。然后就没有然后了...
其实这种面试,每周都在重复。我也是有点疲惫了。我也才慢慢发现,这个行业牛人不少,但混子更多。随随便便期望薪资就是30K、40K。现在有很多公司都要上大数据平台,给了这些混子更多的空间。
不管如何,持续学习、不断进步是我们得以生存的重要途径。所以,刚好这两天有点时间,跟大家来聊聊SparkSQL源码。因为篇幅有限,没办法展开所有。但大家看完,如果对源码不熟悉,肯定会有所启发。
执行计划
Hive准备表和数据
编写测试代码
执行计划
查看Spark执行日志
JAVA执行命令
日志配置加载
提交Spark应用程序
加载默认executor配置
权限验证
启动Spark重要服务
块管理器
加载SparkSQL元数据
发送广播提交JOB
DAG调度
Task调度
生成代码、完成任务
计划执行流程源码解析
设置断点并启动调试
SparkSession.sqlAPI
丰富的SessionState组件
LogicPlan
ProjectLogicPlan
UnresolvedRelation
Dataset.ofRowsAPI
逻辑执行计划生成器源码解析
逻辑执行计划解析器源码解析
Analyzer组件
解析逻辑执行计划流程
应用规则解析逻辑执行计划
逻辑执行计划优化器源码解析
物理执行计划生成源码解析
源码解析:CodeGenerate代码生成
执行计划Hive准备表和数据createdatabaseifnotexiststest;createtableifnotexiststest.t_name(namestring);insertintotest.t_namevalues(test1),(test2),(test3);编写测试代码
为了方便调试SparkSQL源码,我把SQL语句写在了scala代码中。同时,在程序执行的末尾添加了一个阻塞标准输入。这样我们就可以去查看下Spark的WebUI了。
defmain(args:Array[String]):Unit={valconf=newSparkConfconf.set("spark.hive.enable","true")conf.set("spark.sql.hive.metastore.version","2.3")conf.set("spark.sql.hive.metastore.jars","path")//显示所有的执行计划conf.set("spark.sql.ui.explainMode","extended")valspark=SparkSession.builder().config(conf).master("local[1]").enableHiveSupport().getOrCreate()spark.sparkContext.setLogLevel("INFO")//支持方式valsql="""
select
*
from
test.t_name
""".stripMarginvaldf=spark.sql(sql)df.show()System.in.read()}执行计划查看解析执行计划
==ParsedLogicalPlan==GlobalLimit21+-LocalLimit21+-Project[cast(name#0asstring)ASname#3]+-Project[name#0]+-SubqueryAliasspark_catalog.test.t_name+-HiveTableRelation[`test`.`t_name`,org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,DataCols:[name#0],PartitionCols:[]]
可以看到,执行计划树包含以下几个部分内容:
读取Hive的关系型表(test.t_name),使用的是HiveSerDe2读取,包含了一个name列,没有分区执行计划中使用的表的别名为:spark_catalog.test.t_name查询name#0这一列的数据将name#0这一列转换为String类型,并取别名为name#3最后添加一个limit为21的限制(这个是Spark默认给我们添加上的)查看分析后的执行计划==AnalyzedLogicalPlan==name:stringGlobalLimit21+-LocalLimit21+-Project[cast(name#0asstring)ASname#3]+-Project[name#0]+-SubqueryAliasspark_catalog.test.t_name+-HiveTableRelation[`test`.`t_name`,org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,DataCols:[name#0],PartitionCols:[]]
我们看到,分析后的执行计划只添加了name的类型。解析执行计划仅仅是解析SQL为语法树,在解析执行计划阶段,SparkSQL是不知道列的类型的。
优化后的执行计划==OptimizedLogicalPlan==GlobalLimit21+-LocalLimit21+-HiveTableRelation[`test`.`t_name`,org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,DataCols:[name#0],PartitionCols:[]]
我们发现,优化后的执行计划要比分析后的执行计划简单很多。不会进行类型转换,也无需执行投影查询,保留了SparkSQL默认的LIMIT限制。
物理执行计划==PhysicalPlan==CollectLimit21+-Scanhivetest.t_name[name#0],HiveTableRelation[`test`.`t_name`,org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe,DataCols:[name#0],PartitionCols:[]]
物理执行计划就是真正能够在Spark集群上运行的。
image-查看Spark执行日志日志是非常重要了,这也是我们日常开发、排错必不可少的。此处,我们通过INFO级别的日志,来更细一点的粒度地来看看SparkSQL的执行过程。为了方便分析,我省略掉一些不是特别重要的日志信息。
不要指望,通过看日志了解Spark的所有执行机制,我们这一步就是要看看Spark执行过程有哪些组件是比较重要的。后续有助于我们分析源代码。
JAVA执行命令C:\opt\Java\jdk1.8.0_\bin\java.exe"-javaagent:C:\ProgramFiles\JetBrains\IntelliJIDEACommunityEdition.3.2\lib\idea_rt.jar=:C:\ProgramFiles\JetBrains\IntelliJIDEACommunityEdition.3.2\bin"-Dfile.encoding=UTF-8-classpathC:\Users\China\AppData\Local\Temp\classpath.jarcn.
转载请注明:http://www.sonphie.com/jbby/14147.html