启动流程:
客户端执行启动命令:start-all.sh
1. 首先启动Master节点(master),找到配置的slaves文件,获得需要启动的slave节点
2. 然后启动Worker节点(slave1,slave2)
3. Master节点要求Worker节点向Master发送注册信息
(为什么要注册:Master需要掌握Worker节点的健康状态)
4. Master收到注册信息后将其保存在内存或磁盘,然后与worker建立心跳。
心跳是干啥的:
可以定义心跳时间,比如15秒,每15秒Worker都给Master发送心跳,
告诉Master我还活着,Master有一个timeout方法,如果超过了设定的时间
Worker还没向Master发送心跳,就代表这个Worker节点挂了。
从启动集群的start-all.sh看起:
start-all.sh中调用了start-master.sh和start-slaves.sh
start-master.sh调用了org.apache.spark.deploy.master.Master类
start-slaves.sh调用了start-slave.sh,start-slave.sh调用了org.apache.spark.deploy.worker.Worker类
可以按照上面的路径去idea查看Master类和Worker类了
找类也可以使用快捷键查找:两次shift
如果想要找到代码中的某个内容,使用:ctrl + f
Master类:
master进程的开启就是master类实例化的过程
Master类继承ThreadSafeRpcEndpoint
从这里看通信机制,这就发现了一个很有意思的事情,
很多书都说spark的通信机制使用的是actor或者Akka,其实现在已经actor和akka都不用了。
在最开始的spark中,通讯机制是actor,Master类继承的就是是actor类,
然后通信机制换成了Akka,一直到spark1.6,废弃了actor,
从spark1.6开始,通信机制是akka与netty共存,
但当spark2.0版本之后,akka也被放弃,使用netty传输消息,这是因为
akka的版本问题,如使用akka发送消息,就要求发送端和接收端的akka版本相同,
不够灵活,而且spark使用的akka特性很少,不需要akka发布的新版本,
而且很容易实现,所以就在2.0版本彻底移除了akka,换成了netty
虽然改了很多,但是代码还是很像的,都是提供一些参数来进行初始化操作,
如地址、端口、webUI的端口等
def startRpcEnvAndEndpoint(
host: String,
port: Int,
webUiPort: Int,
conf: SparkConf): (RpcEnv, Int, Option[Int]) = {}
master进程的开启就是master类实例化的过程,开启后它还会监视worker的心跳,
checkTimeout之类方法,检测心跳是否超时,定义的默认是60s
Worker类:
worker进程的开启就是worker类实例化的过程
注意的是worker有个register方法(registerWithMaster),也就是向master节点注册worker节点,
master也有一个receive方法接收它,注册成功后master会回复worker节点,
发送RegisteredWorker消息,这个消息就是一个master的url和一个master的web ui的url,
然后就是发送心跳了,默认是15s发送一次(代码中是60/4)
到这整个集群就启动成功了。