写点什么

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

作者:dclar
  • 2022 年 1 月 13 日
  • 本文字数:3286 字

    阅读完需:约 11 分钟

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

回顾

上一篇,https://xie.infoq.cn/article/3bac4574de003e458556a81d2,对 spark 网络进行了初探,了解了 client 端与 server 端大概的构成,以及一个非常简单的交互模型。


重点

  • 消息分为RpcRequestOneWayMessage两类

  • RpcRequest:client 端发送,需要 server 端进行 response 返回,返回后在 client 端处理完成 response,一去一回,类似于传输层的 TCP 协议

  • OneWayMessage:相反,一去不返的方式,类似于传输层的 UDP

  • server 端对于 request 的 response 返回,使用的是 callback 调用的方式

  • client 端对于收到 response 后,识别到底是对应的哪一个 request,采用的是缓存一个 map 数据结构的方式,通过 requestId 找到相应的 callback 的方式

本篇主旨

对于上图,我们高度抽象成下图。本篇解读当服务端收到消息后


  • 如何把消息传递到 spark 处理业务的核心组件

  • 在这个过程中涉及到的 Dispatcher、endpoint、endpointRef 到底是什么

  • 这些组件是如何相互配合完成工作的

  • 处理RpcRequest和处理OneWayMessage的区别

注意

  • 读者可以用图当作架构说明文档,对照代码一起来看,这样效果最好


网络服务的基础:NettyRpcEnv

对于接收到的消息,打开 spark 核心业务处理的桥接通道就是NettyRpcEnvNettyRpcHandlerreceive方法


回忆 NettyRpcEnv

上一篇https://xie.infoq.cn/article/3bac4574de003e458556a81d2 提到了下面这幅图


我把原图做了一个镜像,网络世界放到了左侧,为了和上面的图可以合成到一起。


  • 可以看到当我们需要通过 client 端访问外面的服务的时候,最终需要使用NettyRpcEnv调用TransportClient,发起的是RpcEndpointRef的 ask 或者 send(这个概念后面细说)

  • 并且,上一篇我也提到了NettyRpcEnv也是构成所有网络服务的基础,下文会细讲


NettyRpcEnv 是消息处理的双工桥梁

NettyRpcEnv是基础,但是充当桥梁的是它构建的其他组件,如RpcEndpointRef,如NettyRpcHandler



再细化一下,选取 2 个有代表性的方法,send、askreceive


和外部网络图合并来理解一下


整体的层次

我们先来总结一个层次图,罗列起来比较能看得清层次感


Spark 的逻辑处理世界的宏观结构

上图中引入和“Spark 的逻辑处理世界”这个概念,到这里就基本上解藕了网络层,来到业务处理的部分

High level 看逻辑处理过程

是的,你没看错,其实大的逻辑处理过程就是这么素颜。我很喜欢把复杂问题先简单化,然后再逐步深入细节,从而避免从入门到放弃,打造一个从入门→兴趣→钻研→成功的过程。



上图中,DispatcherRpcEndpoint是虚线,说明这个调用不是一个线性直接调用的过程,中间涉及到了线程池等复杂调用。

解释 Dispatcher

稍稍有些经验的技术同学看到这个名词一定会想到DispatcherServlet,嗯,是的,我就希望这么记忆这个组件,它的大概功能也基本相当,就是一个前置控制器,拦截请求,匹配后续的操作。

解释 RpcEndpoint (trait)

RpcEndpointtrait,也就是 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,会在DispatcherpostOneWayMessage方法处理,从而最终调用到RpcEndpoint实例的receive方法

  • RpcRequest,会在DispatcherpostRemoteMessage方法处理,从而最终调用到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 中的探活的RpcEndpointRpcEndpointVerifier举例


  1. ip 和 port,用于找到服务器,这个和左侧一样

  2. 消息类型,用于判断到底是用receiveAndReply方法来执行还是用receive方法来执行

  3. 请求的RpcEndpoint的名称,这个很重要,通过这个可以找到到底用那个RpcEndpoint来执行,这个就可以理解成为左侧的@Controller中定义的 path,如/main

  4. 消息体类型,粉色,即,这个消息具体的类型,用于在RpcEndpoint中进行 case calss 的模式匹配见右图


引出 RpcEndpointRef 的概念

通过上面的图,我们可以知道,如果想访问上面例子中的RpcEndpointVerifierRpcEndpoint的话,起码需要 3 个必要条件,即上图中的


  • 1: ip 和 port

  • 3:RpcEndpoint的唯一识别名称:name

  • 4:需要模式匹配的 case class,也就是消息体类型


以上 No.1 和 No.3 的 2 个条件即可唯一识别出可以精准访问到RpcEndpoint,而具体访问到哪个 case class 的模式匹配处理,则需要上面的 No.3 在消息中动态的来指定


spark 将上面的三个东东抽象成了一个结构,叫做RpcEndpointRef,是一个抽象类,其实现类叫做NettyRpcEndpointRef。讲的有点干,我们画个图

RpcEndpointRef 是 RpcEndpoint 的引用

通过 RpcEndpointRef 访问 RpcEndpoint

RpcEndpoint所对应的RpcEndpointRef会被另一台服务器所持有,通过 send 方法的调用来访问到RpcEndpoint本尊。至于下图中,在 client 端是如何获取到RpcEndpointRpcEndpointRef,我们后面会用一个详细的案例来讲述


总结: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 的方式类比了消息处理的过程,方便小伙伴的理解


下一篇,我们详细介绍DispatcherRpcEndpoint的具体流程,这是一个很有意思的过程。

发布于: 2022 年 01 月 13 日阅读数: 58
用户头像

dclar

关注

有技术 有智慧 有胸怀 有眼界 2020.05.29 加入

I am an Artist

评论

发布
暂无评论
大画 Spark :: 网络(2)-上篇-通过网络收取消息的过程_大数据_dclar_InfoQ写作社区