SparkRPC 之RpcResponse处理


概要


Spark RPC之RpcRequest请求处理流程中介绍了spark处理RpcRequest请求的流程在client获取到server的RpcEndpointRef之后,如果是单向的请求,即调用RpcEndpointRef.send方法,则流程完毕,若有返回值,即调用RpcEndpointRef.ask方法,并等待server(接收消息的RpcEndpoint)返回消息。在server返回消息的时候,需要使用RpcCallContext来返回消息。RpcResponseCallback将值返回给client。

RPC 通信时,本质两端都是RpcEndpoint,这里说的server和client是基于通信的主客体来说的。即发送消息的是client,接收消息的是server。server的处理结果返回给client,主要由RpcCallContext、RpcResponseCallback完成,此外RpcResponseCallback在client端负责异步提取结果。查看其UML
在这里插入图片描述

1. 基础概念


Server的处理结果要想reply给Client,需要借助RpcCallContextRpcResponseCallback来实现。RpcResponseCallback在client端负责异步提取结果。UML如下:
在这里插入图片描述

1.1 基础概念之RpcCallContext

如上图,RpcCallContext最终有两个实现类

  • LocalNettyRpcCallContext : 使用scala.concurrent.Promise中的success()方法处理client和server在一台机器的情况
  • RemoteNettyRpcCallContext :用于处理远程server的情况
    这里主要介绍下RemoteNettyRpcCallContext:
1.1.1 RemoteNettyRpcCallContext的定义

在这里插入图片描述
从这里我们可以看到,RemoteNettyRpcCallContext维护了属性RpcResponseCallback,server端处理RpcRequest时调用其onSuccess方法将结果返回给client,client端则调用onSuccess时配合异步返回结果,查看RpcResponseCallback定义

1.2 基础概念之RpcResponseCallback

在这里插入图片描述
RpcResponseCallback只定了两个抽象方法,分别处理成功和错误两种情况

1.2.1 在Client端使用RpcResponseCallback

查看RpcResponseCallback子类RpcOutboxMessage:
在这里插入图片描述
RpcResponseCallback.onSuccess接收外部传入的onSuccess函数,该函数定义在NettyRpcEnv.ask方法中,定义以及在创建RpcOutboxMessage(RpcResponseCallback的子类)时对onSucces()的传入如下 :
在这里插入图片描述
(client, response) => onSuccess(deserialize[Any](client, response))这个匿名函数,作为RpcOutboxMessage的第三个参数,去返回给了RpcOutboxMessage中的onSuccess()函数。这里很奇妙。
在这里插入图片描述

1.2.2 在Server端使用RpcResponseCallback

在Server端的Receive函数里面,也是有使用匿名RpcResponseCallback类的,并且要执行重要的回复Client端ResponseMessage的职责。
在这里插入图片描述
并且在后续返回消息过程中,会使用到这里onSuccess()函数来调用TransportRequestHandler的respond(RpcResponse)来从Channel返回Response给Client。这也就是为什么说server端处理RpcRequest时调用其onSuccess方法将结果返回给client,client端则调用onSuccess时配合异步返回结果
在这里插入图片描述

1.2.3 RpcResponseCallback总结

总体而言,在client.ask()与server.receive()中都会去使用RpcResponseCallback。不同之处在于:

  • client.ask()是通过RpcOutboxMessage继承RpcResponseCallback来,并重写onSuccess()方法传入RpcOutboxMessage来实现的
  • server.receive()是通过给receive函数传入一个匿名RpcResponseCallback内部类来实现的。这个匿名内部类会重写onSuccess()方法,等待Server端各种处理逻辑(注册、清除等)完成之后,才会在ReceiveAndReply()中去调用这个onSuccess(),让onSuccess()去给Client端发送Response,从而Client端调用onSuccess()接收到此Response。从而形成完整的闭环。

2. RpcResponse处理流程


这里,篇幅所限,无法展示完整的图,因此有需要可以下载完整的图Client与Server基于Rpc通信底层流程图
RpcResponse处理流程的分析位于下面的步骤3中,为了更好理解整个过程,我们从请求开始,完整分析

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

2.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 ChannelwriteAndFlush方法发送给远程server,信息内容为requestId + message

2.2 server处理RpcRequest,返回带requestId的RpcResponse

client通过channel发送请求给server,server端TransportChannelHandler处理收到的请求,我们在Spark RPC之RpcRequest请求处理流程中有介绍,流程如下 :
在这里插入图片描述
在这里插入图片描述
如上图,流程终于Inbox.process方法,接着分析process方法
在这里插入图片描述
Endpoint处理完信息后,依次调用RemoteNettyRpcCallContext、RpcResponseCallback方法返回信息,查看其实例化信息
在这里插入图片描述

在这里插入图片描述
上图可以看到RpcResponseCallback通过匿名内部类的方式实例化,同时还看到server返回的RpcResponse包含了请求的requestId,对应的respond方法如下
在这里插入图片描述
至此,我们跟踪了server端处理RpcRequest(requestId, message),返回RpcResponse(requestId, message)的流程,至于具体的请求内容和处理结果,和具体的Endpoint实现有关,如Master和Worker,可以查看Spark RPC之Master实现,Spark RPC之Worker实现中receiveAndReply方法逻辑。

2.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注册的例子
    在这里插入图片描述

3. 总结

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

  1. client端调用RpcEndpointRef.ask方法发送RpcRequest请求。
  2. server端处理RpcRequest,并返回RpcResponse。
  3. client端处理返回的RpcResponse。
  4. 并介绍了上述过程如何使用requestId跟踪请求。此外,介绍了RpcCallContext、RpcResponseCallback如何在server端发挥作用,返回RpcResponse给client,以及RpcResponseCallback在client异步处理数据。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值