spark 2.4.0源码分析--(四)Spark Netty RPC实现及Endpoint

本文深入剖析Spark 2.4.0中Netty RPC环境(NettyRpcEnv)的实现,包括Netty Rpc的总体流程、客户端发送数据及outboxes机制、服务器接收数据与dispatcher处理。通过NettyRpcEndpointRef的send和ask方法理解消息发送,详细阐述了dispatcher如何分发消息以及Endpoint的响应处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、主线NettyRpcEnv

上一篇文章,我们分析了Spark Netty在数据传输层相关的实现,及Transport命令相关的类,包括TransportConf、TransportContext、TransportServer、TransportClientFactory、TransportChannelHandler。这些介绍的主要类,均在NettyRpcEnv中创建了成员变量。
在本文,我们将分析NettyRpcEnv中对上述类的包装及使用,即如何实现RPC

1、Netty Rpc总体流程

在这里插入图片描述

序号①为一个本地发送消息的特例,表示通过NettyRpcEndpointRef的ask和send方法,向本地节点的RpcEndpoint发送消息,由于是同一节点,直接调用Dispatcher的postLocalMessage或postOnewayMessage方法,将消息放入EndpointData内部的Inbox的Message列表中。Message-Loop线程最后处理消息,并将消息发送给对应的Endpoint处理。
序号②为一个向远端发送消息的流程,表示通过NettyRpcEndpointRed的ask和send方法,向远端节点的RpcEndpoint发送消息,这种情况下,消息先被封装为OutboxMessage,然后放入到远端RPCEndpoint地址对应的OutBox的messages列表中。
序号③表示每个Outbox的drainOutbox方法通过循环,不断从messages列表中取得OutboxMessage。
序号④表示每个Outbox的drainOutbox方法,使用内部的TransportClient向远端的NettyRpcEnv发送序号③所取得的OutboxMessage
序号⑤表示序号④发出的请求在与远端NettyRpcEnv的TransportServer建立了连接后(即launchConnectTask()创建TransportClient),请求消息首先结果Netty管道的处理,然后经过NettyRpccHandler的处理,最后NettyRpcHandler的receive方法会调用Dispatcher的postRemoteMessage或postOneWayMessage方法,将消息放入EndpointData内部的Inbox的messages列表中,MessageLoop线程最后处理消息,并将消息发送给对应的RpcEndpoint处理。

2、创建NettyRpcEnv

NettyRpcEnv是一个主线类,通过它可以分析:

  • Client数据调用postToOutbox()发送到outboxes进行分发
  • Server端TransportChannelHandler接收到数据,调用NettyRpcHandler的receive()方法,将数据分发到dispatcher中。
  • NettyRpcEnv既有Server相关变量和接口函数,也有Client相关变量和接口函数,一些读者在初步接触时,容易混淆。
  • 事实上NettyRpcEnv既存在于driver创建的SparkEnv中,也存在于executor创建的SparkEnv中,存在于driver时,会默认创建TransportServer,这样就好理解些了。

在这里插入图片描述

上图中标注①,在executor和driver中均创建了NettyRpcEnv,即driver也可以使用client的相关特性,例如向其它远端server发送消息,这里只做了解。

private[rpc] class NettyRpcEnvFactory extends RpcEnvFactory with Logging {
	def create(config: RpcEnvConfig): RpcEnv = {
    val sparkConf = config.conf
    val javaSerializerInstance =
      new JavaSerializer(sparkConf).newInstance().asInstanceOf[JavaSerializerInstance]
    val nettyEnv =
      new NettyRpcEnv(sparkConf, javaSerializerInstance, config.advertiseAddress,
        config.securityManager, config.numUsableCores)
    if (!config.clientMode) {
      val startNettyRpcEnv: Int => (NettyRpcEnv, Int) = { actualPort =>
        nettyEnv.startServer(config.bindAddress, actualPort)
        (nettyEnv, nettyEnv.address.port)
      }
      try {
        Utils.startServiceOnPort(config.port, startNettyRpcEnv, sparkConf, config.name)._1
      } catch {
        case NonFatal(e) =>
          nettyEnv.shutdown()
          throw e
      }
    }
    nettyEnv
  }
}

3、NettyRpcEnv成员变量及方法分类介绍

NettyRpcEnv具有server、client相关特性,按以下图示,进行分类说明:

  • 图中上部分为Server相关实现,包括streamManager、transportServer、dispatcher
  • 图中下部分为Client相关实现,包括clientFactory、outboxes、clientConnectionExecutor

在这里插入图片描述

二、client发送数据及outboxes

1、NettyRpcEndpointRef发送数据接口

NettyRpcEndpointRef提供了send()、ask()方法,用于向server发送单向消息和需要回执的RPC消息,其内部实际上是调用NettyRpc对应的接口:

private[netty] class NettyRpcEndpointRef(
    private val conf: SparkConf,
    private val endpointAddress: RpcEndpointAddress,
    private var nettyEnv: NettyRpcEnv) extends Rp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值