这段时间一直在阅读SparkInternal(https://github.com/JerryLead/SparkInternals)这篇文档,里面很详细的分析了spark的工作原理,但又不是单纯的代码走读,加入了许多作者的理解以及注释,值得刚接触spark的朋友阅读。
一、spark部署概览:
一个典型的spark工作集群图如下:
集群分为Master和Worker,相当于hadoop的Master和Slave。话说,spark这么设定,是暗示分布式平台的进步么,奴隶社会(Slave)进步到资本主义社会(Worker).......
在Spark集群中,用户自己编写的一个文件,比如wordcount.scala,就可以视为一个Application。而这个程序中的main函数,则可以视为Driver(官方定义Driver是:一个运行main函数并创建SparkContext的
进程,注意这是一个进程)。一般Driver就在主节点(master)上运行,Yarn集群的话可能被调度到工作节点(Worker)上。对于一个Driver进程,它往往对应着多个executor对象。每个工作节点中有一到多个ExecutorBackend 进程。每个进程包含一个 Executor 对象,该对象持有一个线程池,池子中每个线程可以执行一个 task。
这样一来,一个用户自己编写的Application,就包含一个Driver,多个executor,而每个executor中,又包含多个具体用来处理数据的task。
二、spark工作流程概览:
对于mapreduce而言,工作流程是固定的。用户需要做的只是在map部分写入对应的代码,在reduce部分写入另一部分代码即可。但对于spark而言,内部的处理流程更加复杂。
首先需要建立逻辑执行图(数据依赖图),在这张图中,可以明确看到原始数据是如何经历一个个RDD的变化,最终得到输出的。如下图:
得到了上面的数据依赖之后,就要开始具体的task划分。但正如之前提到的,spark和mapreduce不同,它内部处理更加灵活,因此无法将上面的数据流动直接用task这种物理形式表现,所以要将数据依赖图转换为下面的task物理执行图。
最后,再在物理执行图中,划分出具体的task,再交付给机器运行。