写点什么

大画 Spark :: 网络 (5)-Spark 中的 server 端和 client 端

作者:dclar
  • 2022 年 3 月 07 日
  • 本文字数:2711 字

    阅读完需:约 9 分钟

大画 Spark :: 网络(5)-Spark中的server端和client端

回顾

上一篇介绍了 Endpoint 的构建流程,采用sparkEnvNettyRpcEnvDispatcher的构建顺序。并且探讨了最基础的 Driver 和 Executor 的职责与关系




本篇主旨

介绍在 Drvier 端是如何构建起 Netty 的 server 服务,以及在 client 端又是如何构建起 client 服务的过程


可能会涉及到一些Netty的知识,我会穿插做基础知识的介绍。

整体的构建结构

Driver(server)和 Executor(client)双方的构建方式基本相同,结构如下

构建源的区别

Driver

Driver 的构建采用的是从sparkContext的开始进行构建,它可以理解成是用户程序与 spark 集群的 entry point(这个是源代码中的 class 头注释),用户程序与 spark 进行交互时,都要先声明sparkContext,读取数据的操作包括 RDD 也都是从sparkContext开始一步步的衍生而来,这些概念后续聊。

Executor

Executor 的构建,是从一个叫做CoarseGrainedExecutorBackend的 class 中开始的,这个类是 Executor 在某一台服务器上执行的进程 class,可以在这个类中看到main方法。


构建 server 和 client

上一篇文章说过,Driver 端充当的是 server 的角色,Executor 充当的是 client 的角色。那么在整个启动和构建环境的过程中也会存在些许差异。


Driver 端构建过程中会启动一个基于Netty的 server 服务,可供 client 端提供主动连接的服务。


这个差异体现在下面


可以看到,在 Driver 构建整个结构的时候,在 NettyRpEnv 的 create 方法调用时会生成出一个 server,这个方法是RpcEnv中的startServer方法,而相同的 Executor 端的操作就不会有 server 构建出来。



这里需要说明一点,因为 spark 采用的是基于 Netty 的 RPC 通信,也就是裸在 TCP 协议上的直接网络连接,所以,server 端只能被 client 端主动连接,而不能 server 端主动连接 client,这个是常识就不多说了。但是一旦获取了稳定连接后,server 端持有了 client 端的 socket 信息,是可以主动向 client 端发送消息的;换句话说一旦连接上,client 端和 server 端相互持有对方的 socket,是双工随时可以向对方发送消息的,这一点不要陷入 http 协议的误区中。因为后续从 Driver 端下发任务给 Executor 其实就是 server 给 client 发消息的过程。


Driver 的 Server 的构建与 Endpoint 设置

看一下 server 构建的一些细节点,并关注在这个过程中,endpoint 是如何通过 Dispatcher 设置好的。


上面说到,server 端和 client 端不同的地方就是startServer的过程,这个方法在RpcEnv中。Netty的 server 构建和 bootstrap 的原理这里就不做介绍了,后续有时间我会再去做一个Netty的介绍,因为Netty涉及到太多的Linux底层和内存的原理,讲清楚真的不太容易。


代码如下


  • 构建 server 的核心是transportContext.createServer的调用

  • 并且这个里面可以看到通过dispatcher设置了一个叫做RpcEndpointVerifier.NAMEEndpoint


def startServer(bindAddress: String, port: Int): Unit = {    val bootstraps: java.util.List[TransportServerBootstrap] =      if (securityManager.isAuthenticationEnabled()) {        java.util.Arrays.asList(new AuthServerBootstrap(transportConf, securityManager))      } else {        java.util.Collections.emptyList()      }    // 这个是核心的过程,通过transportContext的createServer可以构建起一个Netty的server端    server = transportContext.createServer(bindAddress, port, bootstraps)
// 这个过程是通过dispatcher来设置一个Endpoint dispatcher.registerRpcEndpoint( RpcEndpointVerifier.NAME, new RpcEndpointVerifier(this, dispatcher)) }
复制代码


用前面的图可以回忆一下,这是一个非常简单的Endpoint被塞入到Dispatcher的过程,而其他的Endpoint也是通过这个方法设置的,只不过场景和地方不一样,在后续的讲解中会慢慢一个个的涉及。



上述这个叫做RpcEndpointVerifier.NAMEEndpoint是做什么用处的呢?后续我会对一个完整的网络调用流程讲解的时候涉及到这个Endpoint


经过上面startServer的方法的调用,Driver端的 Server 就完全被启动起来了

Server 和 Client 的交互方式

在 Spark 中,一旦创建 Driver 所代表的 Server 端和 Executor 所代表的 Client 端是如何通信的呢?


基本的套路就是


  1. Driver 端首先启动 Server

  2. Executor 的 Client 端需要知道 Server 端的 ip 和 port,联通 Server

  3. 此时 Client 端持有了 Server 的 socket,同样,Server 也持有了 Client 的 socket,所以此时两方是可以随时向对方发送消息的。这块对于学习普通 http 网络的同学来说有点蒙,因为在 http 协议中,我们都是 Client 端发送 Request 请求到 Server 端,然后阻塞的等待 Server 返回,而没有 Server 端向 Client 端主动发送请求的 case,当然,websocket 除外。但,如果从 http 下降一层,我们就裸在 TCP 的上面,首次链接肯定是 Client 发送请求到 Server,经过在 TCP 层的三次握手,Client 端和 Server 端都会持有对方的全网唯一的 Socket,从此之后,双方谁都可以主动给对方发消息,一般来说,网络中肯定是多个 Client 对一个 Server(刨除 HA 的策略),Server 面对多个 Client 同时发送消息会有一些诸如 Netty 中的 NIO 的处理策略,而如果剔除掉这些策略,其实 Server 和 Client 完全对等,相互随时都可以给对方发消息,而收到消息的一方根据商议好的消息体中的类型可以回复或者不回复。了解到这里非常重要,因为后续从 Driver 端给 Executor 下发 task 的时候,其实就是 Server 发送消息给 Client 的过程,和我们平时一直理解的 Client 请求 Server 正好相反

图解一下交互过程

图很简单,想表达的意思就是从 Client 到 Server 端第一次的联通后,后续就是 Server 与 Client 端可以任意发送消息给对方。而关于途中的 1 和 N 的含义具体细化解释如下。

1 的含义

这个从 Client 到 Server 的 1 的含义,仅仅代表第一次的网络请求一定是从 Client 端发起联通到 Server 端的,是一个广义概念。从 TCP 层面来讲,肯定是要进行三次握手的过程。并且,在 spark 中,Executor 端作为 Client 首次与 Drvier 作为的 Server 联通的过程也是一个在 TCP 上层过程的“三次握手”的过程,这个过程在 spark 的源代码中写的非常优雅,下一章我会细聊这部分内容。


综上,初次链接是 Client 端发给 Server 的,也就是 Executor 发给 Driver 的,他们内部还会有一系列业务操作过程确认整个连接在业务层面已经 OK。

N 的含义

这里的 N 是一个双向箭头,即一旦双方建立起连接后,信息可以从任何一方发给对方。在上文也说过,这个过程不要和 http 协议中只有 client 发给 server 的过程弄混。因为 Spark 的网络是在 TCP 上层的自定义协议的封装,没有 http 的阻塞式的限制。


总结

本文主要介绍了在 Spark 中的业务层面的 Driver 和 Client 所代表的技术架构中的 Server 和 Client 之间的消息联通基本原理和过程,有点偏抽象,没关系,下篇我来给大家上一篇干货,从代码细节分析 Executor 是如何去连接 Driver 的,全部用图来画出,方便理解和记忆。

发布于: 刚刚阅读数: 2
用户头像

dclar

关注

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

I am an Artist

评论

发布
暂无评论
大画 Spark :: 网络(5)-Spark中的server端和client端_大数据_dclar_InfoQ写作平台