概要
RPC是分布式项目的基石,Spark RPC被deploy、scheduler、shuffle、storage等多个模块使用,是学习这些模块的前提。其最初使用akka的actor实现,并在spark1.4版本标准化了rpc相关接口,具体参考这里。标准化这套接口为了能够实现基于其他技术的rpc方案,并且最终也是这么做的,在spark1.6版本中rpc的默认实现由基于akka的actor转变为基于netty,解决了实际项目中可能存在的akka版本问题,具体讨论参考这里。
akka actor简介
为什么介绍actor?
最新版本rpc默认实现已经是基于netty了,所以我们是不是不再需要了解akka actor了呢,并不是,上面说到了spark1.4标准化了rpc的接口,这套接口其实就是仿照actor的,无论是class还是method都能和actor对应上,因此,简单了解akka的actor对于理解Spark RPC能起到事半功倍的作用。
actor中几个重要概念
对于actor陌生的同学参考下官方doc,这里我们以一个例子简单熟悉下actor中三个重要的概念,ActorSystem、Actor和ActorRef
如上图,我们自定义了HelloActor用于处理信息,接着在main函数中实例化ActorSystem,调用其
actorOf方法注册我们定义的actor并取名为hello,返回这个actor的引用actorRef,利用这个引用和actor通信,接下来发送消息“Smith”给actor,HelloActor接收到信息并打印到屏幕,至此最简单的actor例子就执行完成了,接下来我们熟悉下rpc的接口。
rpc接口
概要中提到了spark1.4规范了rpc的接口,该规范根据akka的actor抽象出三个重要的接口,并且和actor中class对应关系如下
RpcEndpoint => Actor
RpcEndpointRef => ActorRef
RpcEnv => ActorSystem
-
RpcEndpoint
RpcEndpoint对应actor例子中的Actor,用于处理信息。
其有两个重要方法,receive和receiveAndReply,区别是后者处理完信息后会返回信息给发送者,类似tcp和udp。
再看actor例子中我们定义的HelloActor,其处理信息的方法名正是receive,一个RpcEndpoint的生命周期如下: onStart -> receive(receiveAndReply) -> onStop*,剩下几个方法分别是处理连接建立断开和错误事件。
deploy 模块的 Master、Worker 是RpcEndpoint的具体实现,查看Spark RPC之Master实现、Spark RPC之Worker实现。
-
**RpcEnv **
RpcEnv对应actor例子中的ActorSystem,注册并维护RpcEndpoint和RpcEndpointRef。
主要方法为setupEndpoint,用法上对应例子中ActorSystem的actorOf方法,用于注册RpcEndpoint。
也提供了多种获取RpcEndpointRef的方法,如asyncSetupEndpointRefByURI、setupEndpointRefByURI和setupEndpointRef,以及移除RpcEndpoint的方法stop,关闭RpcEnv的方法shutdown,其还维护了RpcEnvFileServer,用于上传下载jar和file。
最后,实例化RpcEnv时,需指定是server模式还是client(默认是server),server模式下底层启动netty,参考Spark RPC之Netty启动。
-
RpcEndpointRef
RpcEndpointRef对应actor例子中的ActorRef,向对应的RpcEndpoint发送信息
主要方法send和ask,send方法只发送信息,ask方法发送信息的同时接受返回值,ask方法又有几个相似方法,涉及到retry和timeout。
此外,还有两个属性address和name,用于对应这个RpcEndpointRef所属的RpcEndpoint。
RpcEndpointRef 是抽象类,NettyRpcEndpointRef是其具体实现,内部使用Dispatcher、Inbox、Outbox等组件发送信息,具体流程参考Spark RPC之RpcRequest请求处理流程、Spark RPC之Dispatcher、Inbox、Outbox。
RpcAddress 和 RpcCallContext
-
RpcAddress
RpcAddress用于维护host和port,以及sparkURL格式和其他格式之间的转换,定义如下
-
RpcCallContext
RpcCallContext 作用于RpcEndpoint中,当RpcEndpoint调用receiveAndReply处理完信息后,使用RpcCallContext的reply方法将处理结果返回。具体请参考Spark RPC之RpcResponse处理中关于RpcCallContext的介绍,定义如下
关系图如下 :
最后给出一个spark关于rpc的unit test帮助理解上述接口的使用,和akka的例子参照着看,更多的unit test查看这里。
总结
介绍了Spark RPC的接口,重点介绍了RpcEnv、RpcEndpoint和RpcEndpointRef,以及其和akka actor的渊源,这组接口使用上和akka actor极为相似,底层使用netty实现。
参考:https://blog.csdn.net/u011564172/article/details/55823670
deploy模块的Master、Worker是RpcEndpoint的具体实现,查看Spark RPC之Master实现、Spark RPC之Worker实现。
最后,实例化RpcEnv时,需指定是server模式还是client(默认是server),server模式下底层启动netty,参考Spark RPC之Netty启动。
NettyRpcEndpointRef是其具体实现,内部使用Dispatcher、Inbox、Outbox等组件发送信息,具体流程参考Spark RPC之RpcRequest请求处理流程、Spark RPC之Dispatcher、Inbox、Outbox。