spark源码学习(六):standalone模式的cluster集群源码解读
在spark任务的提交的那片blog中,我们仅仅谈到了executor相关的概念:Execuor会向driver注册,然后driver在给它对应的注册信息成功的消息。但是在spark的生态系统中,Driver Application,master,worker,executor,到底是怎样相互通信的呢?通信的具体流程又是如何的呢?看看下图我们在稍作解释:
上图的案例启动过程主要是standalone模式下的cluster方式启动各个进程,注意的是,这里的driver不能运行在client的内部,他只能独立的运行。那么我们就可以说,在cluster模式下,在集群运行起来之后,就算你driver挂掉了,也不会影响我任务的运行,只不过resultTask最后的运行结果无法提交而已。我们来看看具体的启动流程:
刚开始最重要的就是开启集群中的各个Executor之后才能进行任务的提交,否则根本无法运行任务。所以,第一步是由worker节点去向Master注册。当然我们是先启动master(sbin/start-master.sh),然后再启动worker(sbin/start-worker.sh spark://localhost:7077)。上面的两条命令就开启了master和worker节点,但是这时的Executor并没有被创建 。要知道Executor不是被显示的拉起来的,而是在外界的“刺激”下才会被Master带起来。例如我么运行一下spark-shell就会创建Executor,因为spark-shell就属于Application。具体调度如下spark-shell-->spark-submit-->spark-class.
先来看啊可能这master和worker的创建和初始化过程吧,先看看master:
上面的代码片段是master中的prestart方法,它是在创建master的时候第一个启动的方法,我们会看到一些log日志信息写的很清楚,开始运行spark master进程,其他就是一些相关监控信息的注册和文件系统的选择。之后我们启动了worker:
worker启动的代码和master不同之处就是他没有那么多的监控信息,但是他却有一个很重要的方法,register-WithMaster方法,就是试图注册master,为啥是是试图呢?那就进去看看:
也就是说,当我们发现一个master是活动的,不一定当前的worker就肯定就能去去注册,不管成功与否。try-RegisterAllMasters才是去真正的向当前的master去注册的函数。系去看看吧:
看看这里的日志信息就明白了:"连接master"。主要就是通过一个actorSelection去寻找对应的收信地址,就是master的地址,然后用actor ! RegisterWorker发送消息,包括当前worker的id,host,port等等。
在master收到信息之后回做怎样的处理呢?来看看:
上面的代码可以看出,master自接收到信息之后,就会把worker发送过来的节点信息包装成workerInfo变量,在判断当前的master里面并没有这个worker之后才会向这个worker发送注册成功的信息,继而进行调度Sechedule。
schedule函数是master与worker交互的重中之重,当集群中的资源worker有所改变或者一个新的appclient提交的时候,这个函数都会被调用一次,例如在master接收到新的worker节点会调用这个函数,而有新的appclient的提交也会调用这个函数。schedule主要就是资源的分配,说白了就是master如何把各个workers上的资源分配个app应用程序,具体的待会再看。讲到这里我们仅仅完成了第一幅图的前两个操作,那么下面就来看看app是如何提交给master的。先介绍一下appclient:是一个允许app与集群交互的接口。看看他的prestart函数:
又是刚刚的那个函数,想必你已经很熟悉了,那就不罗嗦,至今进入tryRegisterAllMasters去看看吧:
这个和上一个的处理方式肯定不同,只是因为这里我们注册的是App的应用程序而已。那就去master里面看看具体是如何处理的,你会发现它肯定会调度schedule函数:
这里首先有一个容错处理函数,保证不是同一个app多次提交,然后发送注册成功的消息,再次调用schedule函数。我们就来看schedule( )函数:
这个方法首先是遍历各个worker,用shuffle打乱之后,为每一个workers都去添加一个driver,继而在发送launchDriver之后。worker就会产生一个DriverRunner来运行driver.
deiverRunner也就是一个driver的管理器,包括在driver失效的时候重新启动driver。driverRunner仅仅存在于standalone模式下的cluster。是时候看看master到底是如何调度资源的:startExecutorsOnWorkers负责如何实现资源的分配,有两种方式spreadOut和非spreadOut方式。allocateWorkerResourceToExecutors负责把资源分配给worker。
第一种就是尽最大程度的把资源分给每一个worker上的executor,就是资源都会分给所有的executor。第二种就是先紧着一个executor分配资源,尽量适应较少的executor,具体代码注释掉了。最终都调用了allocateWorkerResourceToExecutors分配资源。
这里的launchExecutor就是第一幅图的第四步,master向worker发送launchExecutor。至于Executor的分发和注册registerExecutor下次再说。