Bootstrap

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

回顾

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

本篇主旨

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

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

整体的构建结构

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

构建源的区别

Driver

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

Executor

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

构建server和client

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

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

这个差异体现在下面

可以看到,在Driver构建整个结构的时候,在NettyRpEnv的create方法调用时会生成出一个server,这个方法是中的方法,而相同的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端不同的地方就是的过程,这个方法在中。的server构建和bootstrap的原理这里就不做介绍了,后续有时间我会再去做一个的介绍,因为涉及到太多的底层和内存的原理,讲清楚真的不太容易。

代码如下

  • 构建server的核心是的调用

  • 并且这个里面可以看到通过设置了一个叫做的

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))
  }

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

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

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

Server和Client的交互方式

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

基本的套路就是

图解一下交互过程

图很简单,想表达的意思就是从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的,全部用图来画出,方便理解和记忆。