Spark通信--client、master、worker间的通信

1、构建RDD
2、构建DAGScheduler
3、构建TASKScheduler
4、提交到worker
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
1.首先通过Spark-shell 提交任务的时候,启动Spark-Submit类,然后通过反射调用自定义的app的main方法。
2、在WC的main方法中,加载默认的配置,SparkConf,接着创建非常重要的SparkContext,它是通往集群的入口。
3、在SparkContext中完成了重要的三件事情,创建Spark-env(创建ActorSystem,用于创建DriverActor和ClientActor)构建DAGScheduler和TaskScheduler。
4、通过SparkEnv来创建createDriverEnv,调用自己的Create方法来创建createDriverEnv.这里调用了CreateDriverEnv,返回一个SparkEnv对象,这个对象里面有很多重要的属性,最重要的就是ActorSystem。
5、创建TaskScheduler(createTaskScheduler),这里有很多的正则表达式,用来匹配模式,根据URL选择不同的方式。SPARK_REGEX,spark的standalone模式,首先new TaskSchedulerImpl。
6、接着val backend = new SparkDeploySchedulerBackEnd,初始化了一个调度器,默认是FIFO.
7、scheduler.initialize(backend) (backend,scheduler).
8、在TaskSchedulerImpl中用backend调用start方法。
9、在SparkDeploySchedulerBackEnd中,为启动java子进程准备一些参数,val command = new Command(“org.apache.spark.executor.CoarseGrainedExecutorBackend”,args, sc.executorEnvs, classPathEntries ++ testingClassPath, libraryPathEntries, javaOpts),用command拼接参数,最终会启动CoarseGrainedExecutorBackend。
10、用ApplicationDescription封装了一些重要的参数,放到appDesc中,接着创建DriverActor,client.start()启动ClientActor.
11、这里需要注意一个继承结构,SchedulerBackEnd—->CoarseGrainedSchedulerBackend—>SparkDeploySchedulerBackend
12、在CoarseGrainedSchedulerBackend中,通过actorSystem.actorOf创建DriverActor,它是用于跟当前的app产生的Executor通信。
13、到目前为止DriverActor和ClientActor都已经创建好了,接着就是通信了。
注意(CoarseGrainedSchedulerBackend)DriverActor首先创建,(SparkDeploySchedulerBackend)ClientActor后面创建。
14、ClientActor向Master发送注册消息,模式匹配。在ClientActor的preStart方法中向master注册(registerWithMaster)通过actorSelection拿到master的引用,actor ! RegisterApplication(appDescription)向master发送异步消息。
15、在master中接受到注册消息之后,ApplicationDescription中包含了需要的资源,将来要启动的实现类和一些参数。首先进行一些判断,接着将app放到集合当中。如果有zookeeper,则持久化到磁盘当中。然后向ClientActor反馈消息。ExecutorAdded master向ClientActor反馈消息,告诉Executor添加完成。
16、接着master进行调度,schedule()很重要。在master的主构造器中,启动定时任务,有一个保存workerInfo的hashset,一个用于保存workid和workerinfo的hashmap,还有一个hashset用于保存客户端也就是spark-submit提交的任务,还有等待调度的app,保存driverinfo。主构造器执行完成之后会执行prestart方法,当然这里面还有receive方法,prestart方法中订阅事件,启动定时器,定期检查超时的worker,这里重点看一下重点看一下CheckForWorkerTimeOut。在receive方法中,接受worker的注册信息,首先判断worker是否已经注册过了。
17、没有注册过,将worker的信息保存到wokerinfo中,workerinfo相当于一个类,这是个封装类。
//向Worker反馈信息,告诉Worker注册成功
sender ! RegisteredWorker(masterUrl, masterWebUiUrl)
18、然后进行任务的调度,schedule()这个方法很重要,有两种调度模式,一种是尽量打散,一种是尽量集中,也就是榨干机器的资源。首先来看看,尽量打散的方式,spreadOutApps,过滤所有的workerinfo(worker是alive的状态,其次worker的剩余cores大于所需要的cores,最后当前的executor中没有该任务的子进程)创建了一个数组,数组的长度为可用worker的数量,里面的内容是0,最后根据worker的资源情况,数组中是(1,1,1)(2,2,2)
(3,3,3)……(n,n,n)这样的分配。
19、封装executor的描述信息,开始启动executor(launchExecutor),然后向worker发送启动executor的命令,传递一些参数启动的实现类(因为这个启动以后有可能在yarn上,也有可能在其他的方式中启动)。还会向ClientActor发送消息,告诉executor启动了。
20、worker拿到命令之后就去启动executor,appDesc中包含了一些启动的参数、需要启动的实现类。
21、worker new ExecutorRunner 启动一个线程帮助worker启动executor(异步,worker可以进行其他的任务,而不是等待结果的返回), manager.start()启动。
22、然后向master发送消息ExecutorStateChanged。
23、preStart()方法中executor主动向DriverActor注册,然后DriverActor进行makeOffers(),把task序列化,把序列化好的task发送给executor,在receive方法中有DriverActor发送过来的LaunchTask(//DriverActor发送给Executor的启动Task的消息)。在executor中,将task反序列化,启动task,executor.launchTask(this, taskId = taskDesc.taskId, attemptNumber = taskDesc.attemptNumber,taskDesc.name, taskDesc.serializedTask),把task的描述信息放到TaskRunner中,然后将RunnerTask丢到线程池里面进行具体的业务处理。
DAGScheduler:
生成stage getShuffleMapStage registerShuffleDependencies(注册shuffle和依赖) val stage 真正创建一个stage,new一个stage返回一个stage。private def newStage()这个很重要,用来切分stage,首先得到所有的父stages,这里是切分stage的核心算法,val parents = new HashSet[Stage] val visited = new HashSet[RDD[_]],遍历所有的依赖,有两种匹配方式,宽依赖和窄依赖。newstage的时候用到了递归算法,递归的时候需要有一个出口,这个出口就是当没有依赖的时候,也就是第一个stage。
划分stage的原则:
1、看是否是宽依赖
2、分区数量是否相等
3、上一个数据是否是通过group得到的
随后将job丢到任务队列里面,DAGscheduler的runjob方法。传说中的DAGscheduler出现了,提交job返回一个回调器。submitStage()很重要,采用递归的方式提交stage。
这里还需要澄清一个概念:栈,压栈,弹栈。栈的原则是:先进后出,这个和队列正好相反,队列是先进先出。
Client:提交作业。
Master:接收作业,启动Driver和Executor,管理Worker。
Worker:管理节点资源,启动Driver和Executor。
Spark通信--client、master、worker间的通信_第1张图片
(1)Client to Master
RegisterApplication:注册应用。

(2)Master to Client
RegisteredApplication:注册应用后,回复给Client。
ExecutorAdded:通知Client Worker已经启动了Executor,当向Worker发送Launch-Executor时,通知Client Actor。
ExecutorUpdated:通知Client Executor状态已更新。

(3)Master to Worker
LaunchExecutor:启动Executor。
RegisteredWorker:Worker注册的回复。
RegisterWorkerFailed:注册Worker失败的回复。
KillExecutor:停止Executor进程。

(4)Worker to Master
RegisterWorker:注册Worker。
Heartbeat:周期性地Master发送心跳信息。
ExecutorStateChanged:通知Master,Executor状态更新。

你可能感兴趣的:(spark)