1.简介
在Spark中,不同组件像driver,executor,worker,master(stanalone模式)之间的通信是基于RPC来实现的。Spark 1.6之前,Spark的RPC是基于Akka来实现的。Akka是一个基于scala语言的异步的消息框架。Spark1.6后,spark借鉴Akka的设计自己实现了一个基于Netty的rpc框架。本文主要对spark1.6之后基于netty新开发的rpc框架做一个较为深入的分析。
2.整体架构
3.核心组件
3.1 RpcEnv
在介绍RpcEnv之前,我们先介绍SparkEnv。SparkEnv是Spark的执行环境对象,其中包括与众多Executor执行相关的对象。Spark 对任务的计算都依托于 Executor 的能力,所有的 Executor 都有自己的 Spark 的执行环境 SparkEnv。有了 SparkEnv,就可以将数据存储在存储体系中;就能利用计算引擎对计算任务进行处理,就可以在节点间进行通信等。
RpcEnv为RpcEndpoint提供处理消息的环境。RpcEnv负责RpcEndpoint整个生命周期的管理,包括:注册endpoint,endpoint之间消息的路由,以及停止endpoint。
private[spark] abstract class RpcEnv(conf: SparkConf) {
/**
* RPC远程终端查找的默认超时时间,默认为120s
*/
private[spark] val defaultLookupTimeout = RpcUtils.lookupRpcTimeout(conf)
/**
* 返回已经注册的[[RpcEndpoint]]的RpcEndpointRef。
* 该方法只用于[[RpcEndpoint.self]]方法实现中。
* 如果终端相关的[[RpcEndpointRef]]不存在,则返回null。
*/
private[rpc] def endpointRef(endpoint: RpcEndpoint): RpcEndpointRef
/**
* 如果是服务器模式,则返回当前服务器监听的地址;否则为空
*/
def address: RpcAddress
/**
* 使用一个name来注册一个[[RpcEndpoint]],并且返回它的[[RpcEndpointRef]]对象。
* [[RpcEnv]]并不保证线程安全性。
*/
def setupEndpoint(name: String, endpoint: RpcEndpoint): RpcEndpointRef
/**
* 通过一个URI来异步检索[[RpcEndpointRef]]对象
*/
def asyncSetupEndpointRefByURI(uri: String): Future[RpcEndpointRef]
/**
* 通过一个URI来同步检索[[RpcEndpointRef]]对象
*/
def setupEndpointRefByURI(uri: String): RpcEndpointRef = {
defaultLookupTimeout.awaitResult(asyncSetupEndpointRefByURI(uri))
}
/**
* 根据`address` 和 `endpointName`对 [[RpcEndpointRef]]进行同步检索。
*/
def setupEndpointRef(address: RpcAddress, endpointName: String): RpcEndpointRef = {
setupEndpointRefByURI(RpcEndpointAddress(address, endpointName).toString) // URI:
}
/**
* 停止指定的[[RpcEndpoint]]对象。
*/
def stop(endpoint: RpcEndpointRef): Unit
/**
* 异步关闭当前的[[RpcEnv]]。
* 如果需要确保成功地退出[[RpcEnv]],在执行[[shutdown()]]之后需要调用[[awaitTermination()]]。
*/
def shutdown(): Unit
/**
* 等待直到[[RpcEnv]]退出。
* TODO do we need a timeout parameter?
*/
def awaitTermination(): Unit
/**
* 如果没有[[RpcEnv]]对象,那么[[RpcEndpointRef]]将不能被反序列化。
* 因此,如果任何反序列化的对象中包含了[[RpcEndpointRef]],那么这些反序列化的代码都应该在该方法中执行。
*/
def deserialize[T](deserializationAction: () => T): T
/**
* 用于返回文件服务器的实例。
* 如果RpcEnv不是以服务器模式运行,那么该项可能为null。
*
*/
def fileServer: RpcEnvFileServer
/**
* 打开一