简要:
本篇博文主要讨论的内容如下;
1. Executor工作原理
2. ExecutorBackend注册源码解密
3. Executor实例化及具体如何工作
前置知识:
为啥Worker不直接启动Executor,而是启动另一个线程来启动Executor?
1. Worker是管理当前机器资源的,当当前机器的资源发生改变的时候,会将消息汇报给Master的。
2. Spark集群中会有很多应用程序,很多应用程序你就需要很多Executor,如果你不是为每个Executor启动一个进程,而是让这些所有的Executor都在Worker里面,那岂不是一个程序崩溃了,其他程序也崩溃了。
AppClient:代表应用应用程序本身;
一:Spark Executor工作原理
1. 需要特别注意是在CoarseGrainedExecutorBackend启动时向Driver注册Executor其实质是注册ExecutorBackend实例,和Executor无关。
2.CoarseGrainedExecutorBackend是Executor运行所在的进程名称,CoarseGrainedExecutorBackend本身并不会完成具体任务的计算,Executor才会完成计算。Executor才是处理Task的对象,Executor内部是通过线程池的方式来完成Task的计算的;
3.CoarseGrainedExecutorBackend是一个进程,里面有一个Executor对象,CoarseGrainedExecutorBackend和Executor是一一对应的;
4.CoarseGrainedExecutorBackend是一个消息通信体(其实现了ThreadSafeRpcEndPoint)。可以发送消息给Driver并可以接受Driver中发过来的指令,例如启动Task等;
5. 在Driver进程有两个至关重要的Endpoint:
a) ClientEndpoint: 主要负责向Master注册当前的程序,是AppClient的内部成员;
b) DriverEndpoint:这是整个程序运行时候的驱动器,例如接收CoarseGrainedExecutorBackend的注册,是CoarseGrainedExecutorBackend的内部成员。
Executor内幕原理和运行流程解密
- CoarseGrainedExecutorBackend通过onStart()发送RegisterExecutor向Driver注册。这里面的ref也就相当于Driver。
override def onStart() {
logInfo("Connecting to driver: " + driverUrl)
rpcEnv.asyncSetupEndpointRefByURI(driverUrl).flatMap { ref =>
// This is a very fast action so we can use "ThreadUtils.sameThread"
driver = Some(ref)
ref.ask[RegisterExecutorResponse](
RegisterExecutor(executorId, self, hostPort, cores, extractLogUrls))
RegisterExecutor此时的命名是有问题的,因为向Driver端注册并不是注册Executor,而是注册ExecutorBackend.
2. Driver要接受ExecutorBackend的注册,也就是接受CoarseGrainedExecutorBackend发来的请求。在DriverEndpoint中会接收到RegisterExecutor信息并完成在Driver的注册。
override