Spark RPC之RpcResponse处理

来源:互联网 发布:我的世界linux启动器 编辑:程序博客网 时间:2024/06/16 08:20

概要

Spark RPC之RpcRequest请求处理流程中介绍了spark处理RpcRequest请求的流程,如果是单向的请求,即调用RpcEndpointRef.send方法时,则流程完毕,若有返回值,即调用RpcEndpointRef.ask方法时,需要使用RpcCallContext
RpcResponseCallback将值返回给client。

RpcCallContext、RpcResponseCallback

server的处理结果返回给client,主要由RpcCallContextRpcResponseCallback完成,此外RpcResponseCallback在client端负责异步提取结果。查看其UML

如上图,RpcCallContext最终有两个实现类,LocalNettyRpcCallContextRemoteNettyRpcCallContext,前者使用scala.concurrent.Promise处理client和server在一台机器的情况,较简单不作介绍,RemoteNettyRpcCallContext用于处理远程server的情况,查看定义

RemoteNettyRpcCallContext维护了属性RpcResponseCallback,server端处理RpcRequest时调用其onSuccess方法将结果返回给client,client端则调用onSuccess时配合异步返回结果,查看RpcResponseCallback定义

RpcResponseCallback只定了两个抽象方法,分别处理成功和错误两种情况,查看子类RpcOutboxMessage

RpcResponseCallback.onSuccess接收外部传入的onSuccess函数,该函数定义在NettyRpcEnv.ask方法中,定义如下

此外RpcResponseCallback还使用了匿名内部类的方式创建对象,后面会看到。

RpcResponse处理流程

RpcResponse处理流程的分析位于下面的步骤3中,为了更好理解整个过程,我们从请求开始,完整分析

 1. client发送信息给server 2. server处理收到信息,返回结果给client 3. client处理server返回的信息

且我们只分析client和server不在一台机器的情况。

1.client发送带requestId的RpcRequest请求

spark使用了client连接池实现netty多路复用,如下

因此一个client会发送不止一个请求,此时需要requestId跟踪请求,处理有返回值的情况。
Spark RPC之Dispatcher、Inbox、Outbox中介绍了client借助于Outbox发起远程请求的过程,如下

如上图,始于NettyRpcEndpointRef.ask方法,终于Outbox.drainOutbox方法,在drainOutbox方法中,while(true)中使用TransportClient发送数据,如下

如上图注释处,我们只关注访问远程server的情况,此时message类型为RpcOutboxMessage,流程如下

  1. 在drainOutbox方法中,RpcOutboxMessage调用sendWith方法,使用TransportClient发送信息。
  2. TransportClient.sendRpc方法中生成requestId,同时将(requestId, callback)信息添加到TransportResponseHandler的outstandingRpcs中,如下,后续client会根据这个requestId处理server返回的信息
  3. 调用Netty Channel的writeAndFlush方法发送给远程server,信息内容为requestId + message。

2.server处理RpcRequest,返回带requestId的RpcResponse

client通过channel发送请求给server,server端TransportChannelHandler处理收到的请求,我们在Spark RPC之RpcRequest请求处理流程中有介绍,流程如下


如上图,流程终于Inbox.process方法,接着分析process方法

Endpoint处理完信息后,依次调用RemoteNettyRpcCallContextRpcResponseCallback方法返回信息,查看其实例化信息


上图可以看到RpcResponseCallback通过匿名内部类的方式实例化,同时还看到server返回的RpcResponse包含了请求的requestId,对应的respond方法如下

至此,我们跟踪了server端处理RpcRequest(requestId, message),返回RpcResponse(requestId, message)的流程,至于具体的请求内容和处理结果,和具体的Endpoint实现有关,如Master和Worker,可以查看Spark RPC之Master实现,Spark RPC之Worker实现中receiveAndReply方法逻辑。

3.client处理server端返回的RpcResponse

和server端类似,创建TransportClient对象时,将TransportChannelHandler注册到底层的netty pipeline中,因此处理server返回数据也是从TransportChannelHandler开始,流程如下

  1. TransportChannelHandler接收server返回的信息,交给TransportResponseHandler处理
  2. handle方法中根据server返回的requestId从集合outstandingRpcs中获取callback对象,这个callback对象是步骤1.client发送带requestId的RpcRequest请求中,client给server发送请求前,调用addRpcRequest(requestId, callback)方法添加进去的。
  3. 调用步骤2中获取到的RpcResponseCallback对象的onSuccess将结果异步返回,此处的RpcResponseCallback对象是RpcOutboxMessage的实例,参考最开始关于RpcResponseCallback的介绍,而server端也有RpcResponseCallback实例化对象,是通过匿名内部类实现的,作用也不同,不要混淆。
  4. 步骤3中处理的结果,调用onComplete方法消费,例如Worker向Master注册的例子

总结

完整的介绍了Spark RPC远程请求过程的底层流程:

  1. client端调用RpcEndpointRef.ask方法发送RpcRequest请求。
  2. server端处理RpcRequest,并返回RpcResponse
  3. client处理返回的RpcResponse。

并介绍了上述过程如何使用requestId跟踪请求。此外,介绍了RpcCallContext、RpcResponseCallback如何在server端发挥作用,返回RpcResponse给client,以及RpcResponseCallback在client异步处理数据。

1 0
原创粉丝点击