大画 Spark :: 网络 (4)-Endpoint 与的注册使用与网络环境的构建
回顾
回顾之前的网络(1)~(3)的部分,可以清晰的得出以下的结论
Spark 的服务之间的通信是通过 Netty 的 RPC 方式联通
Endpoint
是处理网络请求服务的一个端点处理单元,给Endpoint
发送请求,需要在发送方端构建起这个Endpoint
的EndpointRef
,通过EndpointRef
的send
或者ask
来进行操作send
方法是不需要 response 的OneWayMessage
类型ask
方法是需要 response 的RpcRequest
类型接收方接收到请求后,是通过
TransportRequestHandler
→NettyRpcHandler
→Dispatcher
→RpcEndpoint
的调用流来访问到相应的Endpoint
的,这个过程可以参看大画 Spark :: 网络(3)-回复消息机制
OneWayMessage
与RpcRequest
对比
本篇主旨
稍稍描述一下 Driver 和 Executor
如果说到网络,还是需要简单描述一下 Spark 在作业中的执行原理,也需要简单描述一下其内部的逻辑单元。其中最重要的就是 Driver 和 Executor,Driver 和 Executor 也是在作业过程中会不断进行网络通信的组件之一
Endpoint 与 EndpointRef 的注册
前文中一直提及的RpcEndpoint
是如何注册到 spark 的环境当中的,能够被Dispatcher
调用起来?而RpcEndpoint
的影子RpcEndpointRef
又是如何被如何注册到系统中的呢
回顾之前的架构
在上图中,可以看到我们把 spark 的服务分成了 client 端和 Server 端,这个会在后续继续介绍,这里我们先关注 Server 端的部分。
在 Server 端中,有无数个RpcEndpoint
,这些RpcEndpoint
是在系统启动的时候,注册到Dispatcher
中的,先介绍一下这个注册的过程。
RpcEndpoint 的注册
所有的 Endpoint 的注册都是从Dispatcher
中的registerRpcEndpoint
方法中来的。
如下图所示,RpcEndpoint
是通过调用registerRpcEndpoint
的方法,注册到了Dispatcher
的 endpoints 中,当需要使用到Endpoint
的时候,从 endpoints 按照 key 取出 value 的EndpointData
即可。而EndpointRef
的过程同理,
利用 NettyRpcEnv 调用 Dispatcher
Dispatcher 中的方法registerRpcEndpoint
,在 spark 中,很多场景是由 NettyRpcEnv 通过setupEndpoint
的方法调用起来的
这个 NettyRpcEnv,顾名思义,就是 spark 的 RPC 环境的实现。它是对抽象类 RpcEnv 的实现。在前面的章节中,有过这么一个图来表示 NettyRpcEnv 的作用
逻辑上NettyRpcEnv
是 Rpc 的环境,承接了消息的发送与接收。而从整体构建结构上,NettyRpcEnv
也承担了去设置Dispatcher
中的Endpoint
的职责,其重要工作为
设置
Endpoint
进行
send
和receive
的操作
SparkEnv → NettyRpcEnv →Dispatcher
整个构建的结构如图所示,SparkEnv
→NettyRpcEnv
→Dispatcher
的过程
需要简单描述一下 Driver 和 Executor
说了半天的网络过程,必须要简单描述一下 Driver 和 Executor 的概念,否则无法后续推进网络间通信和 client 与 server 的关系了。之前一直画图在说 client 与 server 的关系,但是在 spark 集群中,什么样的节点是 client 什么样的又是 server 呢?这里简单描述一下,主要是讲网络环境的前置知识,后续讲解调度的时候会深入来聊这块。
Spark 的背景
没有 spark 的年代,mapreduce 是分布式计算的王者,记得 2015 年,我在某互联网公司时,还是写 MR 在 yarn 排队。但 MR 的问题在于,速度慢不用说,更大的问题是无法进行 pipeline 的操作,需要一个任务接着一个任务的去人为的调度,如果一个处理复杂一些,中间过程也需要考虑存储为后续再使用做准备。
Spark 的出现,颠覆了这个过程。很多人都对 spark 有误解,一说到 spark 的快,都会说因为利用了内存,但真正的原因并非如此。虽然 spark 可以使用内存缓存数据,但是只要遇到 shuffle,一定会落盘进行文件的读写,一定会进行磁盘 IO,和 MR 没有区别(spark 的数据的预聚合过程也借鉴了 MR)。但 spark 之所以能高效处理,最重要的是,可以形成一个不用反复重新启动 JVM 的 pipeline 的过程,让整个处理流程即使出现了 shuffle IO 也可以一气到底的执行完成,或者说是迭代器模式的非常经典的使用案例,正是因为这个原因才是 spark 最大的性能优势。
Driver 和 Executor 的职责
spark 的代码一般是这样的,借助 scala 的特点,函数式的书写过程,时不时的还会在中间传递几个函数,对于 java 出身的很多程序员会觉得不太友好,阅读和学习起来也需要一些成本。不过当你深入研究后,会发现 scala 和 spark 的结合真的是行云流水,无所不能,减少了很多 java 的冗长,多了很多优雅。
这段代码的意思非常简单,就是根据传入的文件地址,进行 wordcount 的计算,并把结果存储到一个 path 中。即使没有接触过 spark 的同学,看到这段代码应该也很容易能懂。
如果是普通的 java 程序,那么这段代码就按照一行的过程直接处理了,而 spark 则会对其进行“翻译”,变成 map 的过程和 reduce 的代码过程,把这些代码过程序列化后发送到集群的不同的节点上,进行并行的执行,也就是说,我们看到的是一个串行的过程,spark 可以把它变成几个并行处理的过程,后续我会细化这个过程,这里借一幅图来描述。
一行代码,执行进去后,发现是上图的两个过程,一个是 Transform 的过程,类似于 MR 中的 map,后面的 Action 的过程,类似于 MR 中的 reduce 的过程。
spark 会切分我们的代码,并且按照顺序去提交,还要考虑依赖关系,所以就会出现两个概念,一个是类似于 Director 的协调者,另一个就是执行者,这个协调者就是 Driver,执行者就是 Executor
Driver 和 Executor 的构建
无论是 Driver 还是 Executor,都是下面的这个构建的结构
构建后,双方通过 RPC 进行通信,最终接收消息执行的单元都是双方各自的 endpoints 中的 RpcEndpoint
总结
本篇描述了 Endpoint 的注册到 spark 内的过程,简单介绍了 Driver 和 Executor
Next
下一篇,围绕 Driver 和 Executor 的角色,聊一下 Driver 作为 server 端和 Executor 作为 client 端的异同,双方启动的过程以及发送消息的过程是如何处理的,后续会利用一个 Executor 启动后向 Drvier 进行反向注册的过程来整体描述一遍网络处理的过程
版权声明: 本文为 InfoQ 作者【dclar】的原创文章。
原文链接:【http://xie.infoq.cn/article/d81d305e619aab7e90b538fb3】。文章转载请联系作者。
评论