Spark资源调度中的通信流程

本文深入探讨Spark的资源调度,涵盖driver、master、worker和executor的角色及其通信流程。从SparkContext创建TaskScheduler开始,讲解driver如何向master注册应用,启动executor,以及executor如何向driver注册并执行任务。重点解析了CoarseGrainedSchedulerBackend和executor之间的交互,特别是makeOffers方法在任务调度中的作用。文章引用了多个来源,旨在帮助读者理解Spark的资源调度机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spark的调度包括资源调度和任务调度两种。前面介绍过spark的任务调度包括DAGScheduler&TaskScheduler,本文主要介绍资源调度,包括资源调度中涉及的各模块以及它们之间的通信。

Spark中物理节点包括三者,分别是client、master&worker,而与资源调度相关的角色有四个,分别是driver、master、worker和executor。这几个节点与角色之间的关系可以从下面这张图中描述:



Driver:用于运行Spark应用程序,其中的SparkContext是spark应用程序的入口。根据spark任务提交方式的不同,Driver可以运行在不同的物理节点上,通过spark shell提交时,driver运行于master节点,通过spark-submit提交时,driver运行于client端。

worker:集群中任何可以运行Spark应用程序的物理节点,对应物理机,运行一个或多个Executor进程;

Executor:内部是一个线程池,交给Executor的Task都运行在其中的一个线程,线程间共享资源。此外,Executor有一个代理类ExecutorBackend用于与TaskScheduler&TaskSetManager等模块保持通信,这部分涉及任务调度,这里不再详述。

这几个角色之间的启动流程如下:
SparkContext.createTaskScheduler->taskScheduler.start()->SchedulerBackend.start()->new AppClient&start
还有一条线:
AppClient.onStart->向master注册Application(RegisterApplication)->master接收RegisterApplication,调用scheduler,启动driver&executor->调用startExecutorsOnWorks->launchExecutor

这里注意两点:
a):SchedulerBackend的start方法中先调用super.start开启了CoarseGrainedSchedulerBackend。
         在CoarseGrainedSchedulerBackend的start方法中,做了一个重要的事,就是创建dirverEndpoint:



b):还有一个重要的ClientEndPoint,创建于AppClient的初始化过程中。

几个角色接收处理的消息列出如下(均位于各自的receive函数中):
Worker:SendHearbeat、WorkDirCleanup、MasterChanged、ReconnectWorker、LaunchExecutor、ExcutorStateChanged、KillExecutor、LaunchDriver、KillDriver、DriverStateChanged、RegisterWithMaster、ApplicationFinished

CoarseGrainedExecutorBackend:RegisteredExecutor、RegisterExecutorFailed、LaunchTask、KillTask、StopExecutor、Shutdown

AppClient:RegisteredApplication、ApplicationRemoved、ExecutorAdded、ExecutorUpdated、MasterChanged

LocalBackend:ReviveOffers(executor.launchTask)、StatusUpdate、KillTask

CoarseGrainedSchedulerBackend:StatusUpdate、ReviveOffers、KillTask(receive)

CoarseGrainedSchedulerBackend:RegisterExecutor、StopDriver、StopExecutors、RemoveExecutor、RetrieveSparkProps(receive and replay)
(receive无需等待答复,而receiveAndReply则会阻塞线程,直至有答复)

这几个角色之间的主要交互流程如下:
1、driver-> master:提交Application,向master注册并申请资源;
     AppClient.onStart()中通过调用masterRef.send(RegisterApplication(appDescription, self))向master发送消息
     master接收消息后,依次调用createApplication、registerApplication、startExecutorsOnWorkers();
     注意的是startExecutorsOnWorkers中步步调用,完成了为Application分配Executors,并分配计算资源。

2、master->driver:共传递两种消息
     1、告知Application提交成功,回复RegisteredApplication给driver
     2、告知driver Executor分配成功,在startExecutorsOnWorkers的最后发送



3、executor->driver:注册executor,注册成功的消息会发送给CoarseGrainedExecutorBackend用以创建具体executor
     在 CoarseGrainedExecutorBackend的onStart()方法里向driver发送RegisterExecutor消息,这里的ref指代的就是上文的dirverEndpoint。driver会将executor信息存储在executorDataMap对象里,触发 CoarseGranedSchedulerBackend的makeOffers方法,分配pending的tasks(这里makeOffers开始进入任务调度流程,所以说makeOffers方法是资源调度和任务调度相融合的地方)。



这里详细说一下makeOffers方法,该方法是个private方法,会在两处调用:
     1、case ReviveOffers   :TaskScheduler submitTasks时会调用;
     2、RegisterExecutor:上文一旦有executor注册,就看看有没有需要分配的任务;

进入makeOffers方法,它会首先调用scheduler.resourceOffers,resourceOffers负责taskSet进行task的调度分配,分配时尽量按就近原则进行分配,关键代码如下:



4、driver->executor:提交Tasks,由后者执行任务

makeOffers的最后调用launchTasks发布任务,此时是通过 CoarseGranedSchedulerBackend向CoarseGrainedExecutorBackend发送消息,CoarseGrainedExecutorBackend接收到消息后,开始任务的执行操作。

3、dirver->workers:发送appDescription,启动executor子进程

在前文所述的第二条线中,master的scheduler函数完成executor在worker节点上的分配,然后调用launchExecutor向woker.endpoint发出消息以启动executor。



最后感谢flykobe,本文的部分资料来自他的博客,spark采用akka通信,减少了并发带来的死锁问题,提高了并发效率,但阅读起源代码来难度增加不少。希望能和大家一起学习,共同提高。

参考资料:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值