大画 Spark :: 网络 (2)- 上篇 - 通过网络收取消息的过程

回顾
上一篇,https://xie.infoq.cn/article/3bac4574de003e458556a81d2,对 spark 网络进行了初探,了解了 client 端与 server 端大概的构成,以及一个非常简单的交互模型。
重点
消息分为
RpcRequest和OneWayMessage两类RpcRequest:client 端发送,需要 server 端进行 response 返回,返回后在 client 端处理完成 response,一去一回,类似于传输层的 TCP 协议OneWayMessage:相反,一去不返的方式,类似于传输层的 UDPserver 端对于 request 的 response 返回,使用的是 callback 调用的方式
client 端对于收到 response 后,识别到底是对应的哪一个 request,采用的是缓存一个 map 数据结构的方式,通过 requestId 找到相应的 callback 的方式
本篇主旨
对于上图,我们高度抽象成下图。本篇解读当服务端收到消息后
如何把消息传递到 spark 处理业务的核心组件
在这个过程中涉及到的 Dispatcher、endpoint、endpointRef 到底是什么
这些组件是如何相互配合完成工作的
处理
RpcRequest和处理OneWayMessage的区别
注意
读者可以用图当作架构说明文档,对照代码一起来看,这样效果最好
网络服务的基础:NettyRpcEnv
对于接收到的消息,打开 spark 核心业务处理的桥接通道就是NettyRpcEnv的NettyRpcHandler的receive方法
回忆 NettyRpcEnv
上一篇https://xie.infoq.cn/article/3bac4574de003e458556a81d2 提到了下面这幅图
我把原图做了一个镜像,网络世界放到了左侧,为了和上面的图可以合成到一起。
可以看到当我们需要通过 client 端访问外面的服务的时候,最终需要使用
NettyRpcEnv调用TransportClient,发起的是RpcEndpointRef的 ask 或者 send(这个概念后面细说)并且,上一篇我也提到了
NettyRpcEnv也是构成所有网络服务的基础,下文会细讲
NettyRpcEnv 是消息处理的双工桥梁
NettyRpcEnv是基础,但是充当桥梁的是它构建的其他组件,如RpcEndpointRef,如NettyRpcHandler
再细化一下,选取 2 个有代表性的方法,send、ask和receive
和外部网络图合并来理解一下
整体的层次
我们先来总结一个层次图,罗列起来比较能看得清层次感
Spark 的逻辑处理世界的宏观结构
上图中引入和“Spark 的逻辑处理世界”这个概念,到这里就基本上解藕了网络层,来到业务处理的部分
High level 看逻辑处理过程
是的,你没看错,其实大的逻辑处理过程就是这么素颜。我很喜欢把复杂问题先简单化,然后再逐步深入细节,从而避免从入门到放弃,打造一个从入门→兴趣→钻研→成功的过程。
上图中,Dispatcher到RpcEndpoint是虚线,说明这个调用不是一个线性直接调用的过程,中间涉及到了线程池等复杂调用。
解释 Dispatcher
稍稍有些经验的技术同学看到这个名词一定会想到DispatcherServlet,嗯,是的,我就希望这么记忆这个组件,它的大概功能也基本相当,就是一个前置控制器,拦截请求,匹配后续的操作。
解释 RpcEndpoint (trait)
RpcEndpoint是trait,也就是 java 中我们经常说的接口。它有很多的实现类,比如
RpcEndpoint的实现类就是最终实现收到消息,处理这个消息的逻辑业务的部分
Dispatcher 与 RpcEndpoint 的关系
根据上面的描述,可以知道Dispatcher就是根据 message 的类型,选择不同的RpcEndpoint的实现类来执行业务处理
Dispatcher 的构建
上一章的图经过加工就是下图,Dispatcher也是通过NettyRpcEnv构建出来的
构建关系
层次关系
通过下图看层次关系
深入一下 Spark 的逻辑处理世界
NettyRpcHandler→Dispatcher
通过 2 个receive方法联通起Dispatcher。前文说过,因为有单向OneWayMessage和带反馈的RpcRequest,所以会对应 2 个 receive 方法和 2 个 post...Message 方法,如下图所示
NettyRpcHandler→Dispatcher→RpcEndpoint
因为Dispatcher最终会选择一个RpcEndpoint的实例来处理请求,所以会是这样的一种关系,注意,图中的虚线代表不是直接调用,而是“最终会调用到”的意思
OneWayMessage,会在Dispatcher的postOneWayMessage方法处理,从而最终调用到RpcEndpoint实例的receive方法RpcRequest,会在Dispatcher的postRemoteMessage方法处理,从而最终调用到RpcEndpoint实例的receiveAndReply方法
注意图中的 A、B、C
A:代表一个既可以接收
OneWayMessage又可以接收RpcRequest消息的RpcEndpoint实例B:代表一个只可以接收
RpcRequest消息的RpcEndpoint实例C:代表一个只可以接收
OneWayMessage消息的RpcEndpoint实例
所以,通过下图也可以看出
如果一个
RpcEndpoint中包含receive方法, 那么它只可以接收OneWayMessage消息,如果一个
RpcEndpoint中包含receiveAndReply方法, 那么它只可以接收RpcRequest消息如果一个
RpcEndpoint中包含上述 2 种方法, 那么它既可以接收RpcRequest消息也可以接收OneWayMessage消息
解读 RpcEndpoint
说到这里,根据上面的各类图,为了理解RpcEndpoint我们可以做一个技术的横向类比。
先看一个简单的 SpringMVC 的例子
如果访问/main/index 的 RESTful 的接口,则是 AClass 的 method1 来进行处理,这个大家都很清楚。后续会用 SpringMVC 的例子做对比记忆,非常简单。
我们都知道被@Controller注解注释的 class,在 Spring 启动的时候会进行扫描,对所有注释的方法进行管理,对每一个请求进行@Controller到@RequestMapping的 path 的匹配,如下图
通过
/main找到 AClass通过
/index找到 method1,最终由 method1 来处理这个请求
以上的过程就是 SpringMVC 中的基本原理
什么是 RpcEndpoint
先说结论,RpcEndpoint的实例就可以理解为 SpringMVC 中的@Controller注释的类。只不过在 spark 中不是注解,而是需要所有的 class 来实现RpcEndpoint的 trait
定义 RpcEndpoint
RpcEndpoint翻译过来是端点,顾名思义,一个请求可以触及到的最终的目的地。这个目的地也是处理请求的地方
类比 RpcEndpoint 和 SpringMVC 中处理请求的过程
左侧是 SpringMVC 的例子,右侧是 spark 中的RpcEndpoint,很像对吧。我们对比来说
spark 中的消息请求分为 1-4 的 4 个部分
我用一个 spark 中的探活的
RpcEndpoint:RpcEndpointVerifier举例
ip 和 port,用于找到服务器,这个和左侧一样
消息类型,用于判断到底是用
receiveAndReply方法来执行还是用receive方法来执行请求的
RpcEndpoint的名称,这个很重要,通过这个可以找到到底用那个RpcEndpoint来执行,这个就可以理解成为左侧的@Controller中定义的 path,如/main消息体类型,粉色,即,这个消息具体的类型,用于在
RpcEndpoint中进行 case calss 的模式匹配见右图
引出 RpcEndpointRef 的概念
通过上面的图,我们可以知道,如果想访问上面例子中的RpcEndpointVerifier的RpcEndpoint的话,起码需要 3 个必要条件,即上图中的
1: ip 和 port
3:
RpcEndpoint的唯一识别名称:name4:需要模式匹配的 case class,也就是消息体类型
以上 No.1 和 No.3 的 2 个条件即可唯一识别出可以精准访问到RpcEndpoint,而具体访问到哪个 case class 的模式匹配处理,则需要上面的 No.3 在消息中动态的来指定
spark 将上面的三个东东抽象成了一个结构,叫做RpcEndpointRef,是一个抽象类,其实现类叫做NettyRpcEndpointRef。讲的有点干,我们画个图
RpcEndpointRef 是 RpcEndpoint 的引用
通过 RpcEndpointRef 访问 RpcEndpoint
RpcEndpoint所对应的RpcEndpointRef会被另一台服务器所持有,通过 send 方法的调用来访问到RpcEndpoint本尊。至于下图中,在 client 端是如何获取到RpcEndpoint的RpcEndpointRef,我们后面会用一个详细的案例来讲述
总结:RpcEndpointRef → RpcEndpoint
阶段性总结消息到 RpcEndpoint 的流程
以
RpcRequest的消息为例,整个 1-6 的过程如下图所示,下一篇我们会把 5 再做细化的讲解
总结
本篇,我们从串通了从NettyRpcHandler到最后的RpcEndpoint的大概流程,在这个过程中,我们弄清了以下几个概念
Dispatcher:前置控制器,用于选择消息到底发送到哪里RpcEndpoint:处理消息的最终的端点的一个 trait,里面含有处理消息的业务逻辑RpcRequest的消息:调用receiveAndReply方法OneWayMessage的消息:调用receive方法RpcEndpointRef:描述RpcEndpoint的基础信息,包括 ip、port、和 name,利用这三个基本属性可以找到在某一台服务器的RpcEndpoint,利用RpcEndpointRef的 ask 或者 send 方法即可访问当相应的RpcEndpoint我们用了 SpringMVC 的方式类比了消息处理的过程,方便小伙伴的理解
下一篇,我们详细介绍Dispatcher→RpcEndpoint的具体流程,这是一个很有意思的过程。
版权声明: 本文为 InfoQ 作者【dclar】的原创文章。
原文链接:【http://xie.infoq.cn/article/9b7e1ebf236f7a4abcc81311c】。文章转载请联系作者。










评论