Spark - 各个组件的RPC是怎么通信的
基本概念
【Spark - 各个组件的RPC是怎么通信的】在开始之前,先说几个概念:
- RpcEndPoint:RPC分布式的一个实例,他用于指定消息的处理,比如接收消息。
- RpcEndpointRef:RpcEndPoint的引用,也就是说,他指向的是服务端的RpcEndPoint,所以RpcEndpointRef会有服务端的RPC地址。
![Spark - 各个组件的RPC是怎么通信的](https://img.it610.com/image/info9/126555a935a9479fbf367adca21dab91.png)
文章图片
- Inbox:除了RpcEndPoint和RpcEndpointRef(下图太挤了这两个没画),还存储InboxMessage的消息队列。
- EndpointData:包括了RpcEndpoint、NettyRpcEndpointRef及Inbox。
![Spark - 各个组件的RPC是怎么通信的](https://img.it610.com/image/info9/b01f5d8d9db641d9846767bc9356d4d4.png)
文章图片
RpcEndPoint注册 RpcEndPoint实例化并通过Dispatcher注册的时候,就会实例化上面那些组件,并封装一个EndpointData。这里需要注意的是,Inbox组件在实例化的时候,会往messages这个消息队列放入OnStart消息。
当拿到EndpointData后,Dispatcher就会把这个Dispatcher扔到receivers队列中。
除此之前,还会存储EndpointData和名称的映射关系、RpcEndPoint和RpcEndPointRef的映射关系。
![Spark - 各个组件的RPC是怎么通信的](https://img.it610.com/image/info9/4dba787106f040e4bcdee3404835f0cb.png)
文章图片
扔到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。
![Spark - 各个组件的RPC是怎么通信的](https://img.it610.com/image/info9/e6213bbcfb49419a850447b8423798bf.png)
文章图片
客户端请求发送 RpcEndpoint注册后,就可以接受请求了,我们现在看看客户端怎么发送请求的。
客户端在发送消息前,会把消息封装成RequestMessage,然后再判断消息发送的地址是否是当前地址,如果是当前地址,那流程和上面一样,把消息放入inbox,然后存入receivers队列,等待线程消费。
如果是不一样,那就需要把消息进行序列化,并封装成OutboxMessage,交给Outbox进行处理。
和Inbox类似,Outbox也有自己的OutboxMessage消息队列,不断的从队列拿出messages,把消息发送出去。
![Spark - 各个组件的RPC是怎么通信的](https://img.it610.com/image/info9/225c53739c24497da827ed9c33f80b56.png)
文章图片
服务端接收到请求后,就会把消息进行反序列化,然后扔到receivers队列。
总体流程 1、客户端产生一个消息,然后序列化后放入Outbox的队列中。
2、客户端的一个线程把消息取出来,根据服务端的地址,通过netty进行发送
3、服务端接收到消息,把消息进行反序列号,然后通过客户端给定的信息,找到EndpointData。
4、从EndpointData中取出Inbox,并把消息放入到队列。
5、把EndpointData放入receivers队列。
6、线程池中的线程会从receivers队列取出EndpointData,然后调用Inbox的RpcEndPoint对消息进行处理。
7、如果有返回值,就会通过RpcEndPointRef,把消息序列号后,存入Outbox,服务端的线程就会把这个消息返回给客户端。
8、客户端接收消息后,重复第三步骤对消息进行处理。
![Spark - 各个组件的RPC是怎么通信的](https://img.it610.com/image/info9/5403b767be66466089feeed67fe3ec49.jpg)
文章图片
源码思维导图 RpcEnv的创建
NettyRpcEnv#stop
Dispatcher#postMessage
Dispatcher#stop
客户端发送请求
服务端处理请求
推荐阅读
- Spark|Spark 数据倾斜及其解决方案
- 动态组件与v-once指令
- vue组件中为何data必须是一个函数()
- (六)Component初识组件
- 每日PDCA
- Spring|Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件
- vuex|vuex 基础结构
- SwiftUI|SwiftUI iOS 瀑布流组件之仿CollectionView不规则图文混合(教程含源码)
- Vue组件之事件总线和消息发布订阅详解
- 忆非忆