乐趣区

关于spark:Spark-各个组件的RPC是怎么通信的

基本概念

在开始之前,先说几个概念:

  • RpcEndPoint:RPC 分布式的一个实例,他用于指定音讯的解决,比方接管音讯。
  • RpcEndpointRef:RpcEndPoint 的援用,也就是说,他指向的是服务端的 RpcEndPoint,所以 RpcEndpointRef 会有服务端的 RPC 地址。

  • Inbox:除了 RpcEndPoint 和 RpcEndpointRef(下图太挤了这两个没画),还存储 InboxMessage 的音讯队列。
  • EndpointData:包含了 RpcEndpoint、NettyRpcEndpointRef 及 Inbox。

综上,EndpointData 的构造是这样:

RpcEndPoint 注册

RpcEndPoint 实例化并通过 Dispatcher 注册的时候,就会实例化下面那些组件,并封装一个 EndpointData。这里须要留神的是,Inbox 组件在实例化的时候,会往 messages 这个音讯队列放入 OnStart 音讯。
当拿到 EndpointData 后,Dispatcher 就会把这个 Dispatcher 扔到 receivers 队列中。
除此之前,还会存储 EndpointData 和名称的映射关系、RpcEndPoint 和 RpcEndPointRef 的映射关系。

扔到 receivers 队列的 EndpointData 必定不是仅仅就扔在那边的,所以他会有一个线程池来进行解决,这个线程池里会有 N 个叫做 MessageLoop 的线程,会监听 receivers 队列,如果队列里有数据,就会把队列的数据拿进去。
这个数据就是 EndpointData,对 EndpointData 进行解决的,是 EndpointData 外部的 Inbox。
咱们下面说过,Inbox 外面也保护了一个 InboxMessage 的音讯队列 messages,Inbox 就会把 messages 的音讯拿进去,一个个进行生产。这里的音讯都是有本人的类型,比方 RpcMessage、OnStart、OnStop 等等。
下面还提了,实例化 Inbox 的时候,messages 会有一个 OnStart,所以刚开始 Inbox 的 messages 队列就是有货色的,也就是说马上就会执行 OnStart 里对应的办法,也就是 RpcEndpoint 的 onStart。
所以 RpcEndpoint 的生命周期的签名局部就是结构 ->onStart。

客户端申请发送

RpcEndpoint 注册后,就能够承受申请了,咱们当初看看客户端怎么发送申请的。
客户端在发送音讯前,会把音讯封装成 RequestMessage,而后再判断音讯发送的地址是否是以后地址,如果是以后地址,那流程和下面一样,把音讯放入 inbox,而后存入 receivers 队列,期待线程生产。
如果是不一样,那就须要把音讯进行序列化,并封装成 OutboxMessage,交给 Outbox 进行解决。
和 Inbox 相似,Outbox 也有本人的 OutboxMessage 音讯队列,一直的从队列拿出 messages,把音讯发送进来。

服务端接管到申请后,就会把音讯进行反序列化,而后扔到 receivers 队列。

总体流程

1、客户端产生一个音讯,而后序列化后放入 Outbox 的队列中。
2、客户端的一个线程把音讯取出来,依据服务端的地址,通过 netty 进行发送
3、服务端接管到音讯,把音讯进行反序列号,而后通过客户端给定的信息,找到 EndpointData。
4、从 EndpointData 中取出 Inbox,并把音讯放入到队列。
5、把 EndpointData 放入 receivers 队列。
6、线程池中的线程会从 receivers 队列取出 EndpointData,而后调用 Inbox 的 RpcEndPoint 对音讯进行解决。
7、如果有返回值,就会通过 RpcEndPointRef,把音讯序列号后,存入 Outbox,服务端的线程就会把这个音讯返回给客户端。
8、客户端接管音讯后,反复第三步骤对音讯进行解决。

源码思维导图

RpcEnv 的创立
NettyRpcEnv#stop
Dispatcher#postMessage
Dispatcher#stop
客户端发送申请
服务端解决申请

退出移动版