这是我参与「第四届青训营 」笔记创作活动的第5天
这一章我们主要学习spark core原理和spark3.0优化,阅读本文建议有一定的spark基础
首先我们学习spark的运行架构
这里默认下图所有的术语都了解
spark的架构是主从模型:
- Driver作为主节点,通过Main启动sparkcontext,控制整个应用的生命周期
- Worker作为从节点负责启动executor和task的执行
那么简单介绍一下,一个应用被提交到执行中间经历了什么
- 首先用户main函数中创建sparkcontext,然后连接到clusterManager
- clusterManager会根据用户提交的参数,分配executor等资源
- 然后Driver根据代码生成逻辑计划,再转化成物理执行计划,划分多个stage,然后stage划分多个task发到executor去执行
- executor收到task以后,会准备好task需要的资源,在执行task中途会实时的汇报运行状态给driver
- driver会不断更新状态,和发task给executor执行,直到应用执行完毕
如何生成执行计划?
前面我们讲了应用提交后,Driver会根据代码生成logical plan,然后再生成physical plan
那么Driver具体是怎么操作的呢?
首先要学习,spark中RDD的两种依赖关系(宽依赖、窄依赖)
我们认为父RDD中的每个partition和子RDD中的partition是一对一的关系,则是窄依赖,否则是宽依赖
看下图就比较好理解了
接下来我们来学习Driver是如何生成逻辑计划和物理计划的呢?
- 首先RDD创建以后,sparkcontext就会这些RDD对象构建一个DAG**(logical plan)**
- 当RDD.action被触发之后,会提交给DAGScheduler,这个调度器会根据宽依赖划分stage
- 然后每个stage又会根据partition数量生成taskSet,提交给task调度器,调度器把task调度到work节点的executor去
Spark内存管理
下面我们讲一下Spark的内存管理机制,在运行spark任务之前,我们首先就要调整内存的参数设置
Excutor内存主要是Storage和Excution,这两个内存是可以动态调整的,他们的内存空间会互相借用
在设置这些参数的时候,比如说我代码中缓存和广播的数据比较多,那就调大Storage。Shuffle的量比较多就调大Execution
Spark SQL
我们写spark一般用sql写,那么sql是怎么被转化成spark代码,比如rdd的呢?
先解析成sql抽象语法树,然后遍历这个sql树上的节点,对元数据信息进行绑定,生成逻辑计划,然后经过RBO、CBO生成优化后的逻辑计划,然后再生成多个物理计划,然后再根据CBO选择物理计划转化成spark代码
sql的一生在第一节课也讲过了,这里就不再多讲了,我们这一章主要关注的是spark3.0在sql上的优化,这里仅简单介绍
AQE(Adaptive Query Execution)自适应查询
- 动态合并shuffle分区
- 动态调整join策略
- 动态优化数据倾斜
RuntimeFilter
对参与join的表,提前进行分区裁剪或者数据过滤,然后再join
CodeGen
从提高cpu的利用率的角度来进行runtime优化