1.RDD的依赖关系
1.1 WordCount中的RDD
RDD和它依赖的父RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency)。
1.2 窄依赖
窄依赖指的是每一个父RDD的Partition最多被子RDD的一个Partition使用
总结:窄依赖我们形象的比喻为独生子女
1.3 宽依赖
宽依赖指的是多个子RDD的Partition会依赖同一个父RDD的Partition
总结:窄依赖我们形象的比喻为超生
窄依赖:可以理解为独生子女
宽依赖:可以理解为超生
如上图所示,一个文件被textFile后经过两次转换,每次转换后生成的新的RDD都和原分区一一对应,为窄依赖关系。
当map算子计算失败时,可以直接去上一步的RDD中重新计算,而不需要其他的分区参与。但是如果最后的action算子在计算某个RDD时,计算失败,将会到上一层的多个分区中寻找依赖关系,比较麻烦。
stage解决了这个问题,它根据宽依赖和窄依赖的关系进行换分,如上图将存在窄依赖关系的RDD换分成为一个stage。
2. DAG的生成
2.1 什么是DAG
DAG(Directed Acyclic Graph)叫做有向无环图,原始的RDD通过一系列的转换就就形成了DAG,根据RDD之间的依赖关系的不同将DAG划分成不同的Stage,对于窄依赖,partition的转换处理在Stage中完成计算。对于宽依赖,由于有Shuffle的存在,只能在parent RDD处理完成后,才能开始接下来的计算,因此宽依赖是划分Stage的依据。
2.2 DAG在spark中的应用
- 在Spark应用中,整个执行流程在逻辑上会形成有向无环图(DAG)。
- Action算子触发之后,将所有累积的算子形成一个有向无环图,然后由调度器调度该图上的任务进行运算。
- Spark的调度方式与MapReduce有所不同。Spark根据RDD之间不同的依赖关系切分形成不同的阶段(Stage),一个阶段包含一系列函数执行流水线。
- 图中的A、B、C、D、E、F分别代表不同的RDD,RDD内的方框代表分区。
- 数据从HDFS输入Spark,形成RDD A和RDD C,RDD C上执行map操作,转换为RDD D,RDD B和RDD E执行join操作,转换为F,而在B和E连接转化为F的过程中又会执行Shuffle,最后RDD F通过函数saveAsSequenceFile输出并保存到HDFS中。
2.3. Spark的任务提交机制
作业执行流程描述:
1、客户端启动后直接运行用户程序,启动Driver相关的工作:DAGScheduler和BlockManagerMaster等。
2、客户端的Driver向Master注册。
3、Master还会让Worker启动Exeuctor。Worker创建一个ExecutorRunner线程,ExecutorRunner会启动ExecutorBackend进程。
4、ExecutorBackend启动后会向Driver的SchedulerBackend注册。Driver的DAGScheduler解析作业并生成相应的Stage,每个Stage包含的Task通过TaskScheduler分配给Executor执行。
5、所有stage都完成后作业结束。
简单理解:
首先Driver和master通信(提交任务,申请资源,传送driverUrl地址)如 spark-submit xxx.jar --total-executor-cores 2 --executor-memory 512,该命令执行后master会根据提交的信息申请资源;
master主要做几件事情:1拿出所有workers上的资源;2按照资源的大小进行排序;3按照排序顺序取资源;4让worker启动executor。
最后把任务换分为stage,将stage添加到taskSet中。循环taskset,将task下发。