Spark流程的内部实现
1 Spark核心组件回顾
1.1 Driver
Spark驱动器节点,用于执行Spark任务中的main方法,负责实际代码的执行工作。Driver在Spark作业执行时主要负责:
- 将用户程序转化为job
- 在executor中间进行调度任务(task)
- 跟踪executor的执行情况
- 通过UI展示查询运行情况
1.2 Executor
Executor实际上是一个JVM进程中的一个实现对象
主要有两个核心功能:
- 负责运行组成Spark应用的任务,并且将结果返回给驱动进程
- 它们通过自身的块管理,为用户程序中要求缓存的RDD提供内存式存储。RDD是直接缓存在executor的进程内的,因此任务可以在运行时充分利用缓存数据加速运算。
1.3 Yarn cluster的模式
2.组件通讯
一个类似于邮件的收发系统
3.任务调度机制
资源的划分在driver中,划分好了之后就把资源发送给executor中让task执行
3.1 整个spark创建和执行的时序图
3.2 Job、Stage和Task
- Job是以Action方法为界,遇到一个Action方法则触发一个Job
- Stage是Job的子集,以RDD宽依赖(即shuffle)为界,遇到shuffle做一次划分
- Task是stage的子集,以并行度(分区数)来衡量,有多少个分区就有多少个Task
Spark的任务调度总体来说分两路进行,一路是Stage级的调度,一路是Task级的调度
SparkRDD通过其Transactions操作,形成了RDD的血缘关系图DAG,最后通过Action的调用,触发了Job并调度执行。DAGScheduler负责Stage级的调度,主要是将job切分成若干Stage,并将每个Stage打包成TaskSet交给TaskScheduler调度。TaskScheduler负责Task级的调度,将DAGScheduler给过来的TaskSet(放到任务池中)按照指定的调度策略分发到Executor上执行,调度过程中ScheduleBackend负责提供可用资源,其中SchedulerBackend有多种实现,分别对接不同的资源原理系统。
更加细致一点的流程图:
3.3 stage的划分
一个Stage是否提交,需要判断它的父Stage是否执行,只有在父Stage执行完毕后,才能执行当前的Stage,如果没有父Stage,则就从该Stage执行
3.4 Task的调度
TaskSetManager负责监控管理同一个Stage中的Tasks,TaskScheduler就是以TaskSetManager为单位来调度任务的。TaskSetManager就是一个TaskSet的封装,把它封装成这种形式来放入任务池中准备调度。
任务池中的调度方式有两种:先进先出和公平调度。
在Fair模式中有一个rootPool和多个子Pool,各个子Pool中存储着所有待分配的TaskSetManger。
在Fair模式中,需要先对子Pool进行排序,再对子Pool里面的TaskSetManager进行排序,两者继承同一个Scheduler,故使用同一种排序算法。
3.5 shuffle
3.5.1 shuffle和stage
在划分stage时,最后一个stage称为finalStage,它本质上是一个ResultStage对象,前面所有stage被称为ShuffleMapStage。
- shuffleMapStage的结束伴随着shuffle文件的写磁盘
- ResultStage基本上对应代码中的action算子,即将一个函数应用在RDD的各个Partition的数据集上,意味着一个job的运行结束
3.5.2 task的数量3.5.3 SortShuffle
数据在Stage和Stage之间要进行数据的存储和读写,spark使用的就是SortShuffle。
这种方式只产生两个文件,一个索引文件,一个数据文件。文件通过shuffle的过程(排序-溢写-排序)来完成整个文件的全排序。
- bypass运行机制
在map阶段没有预聚合(前提条件),并且在数据量小的时候(当shuffle map的数量小于设定值的时候,默认值200),也可以不使用排序,直接使用hash,通过hash值来快读定位数据所在的位置,来提高效率。