spark下的Task分发

spark下的Task分发

前言

1.不用多说,继续学习任务调度的分发流程O(∩_∩)O。前期学习netty目标也是为了理解spark这一块通信的内容。
2.从边缘地带一步步向中心大陆进军~~。

一、Inbox类

1.inbox就是用来存储inboxmessage以及将该message进行发送出去的类。大神代码写的太优雅了/(ㄒoㄒ)/~~ 。在该构造器中着重关注的对象当然是LinkedList对象了,它装载的就是待发出去的信息,一般都是发到本地的。
2.每一个Inbox都存储了用来处理该message对应的endpoint以及endpointRef引用对象。

在这里插入图片描述

1.1 process方法。

1.专门用来将存储在LinkedList对象下的message发送出去的一个方法。其实它处理这个message信息就是委托了它所持有的endpoint对象帮处理。
2.在这里传入这个dispatcher对象用到的时候仅是发送stop 信息后它需要将当前endpoint进行从其维护的列表里移除然后停止这么一个i行为。

/**
   * Process stored messages.
   */
  def process(dispatcher: Dispatcher): Unit = {
    var message: InboxMessage = null
    inbox.synchronized {
      if (!enableConcurrent && numActiveThreads != 0) {
        return
      }
      message = messages.poll()
      if (message != null) {
        numActiveThreads += 1
      } else {
        return
      }
    }
    while (true) {
      safelyCall(endpoint) {
        message match {
          case RpcMessage(_sender, content, context) =>
            try {
              endpoint.receiveAndReply(context).applyOrElse[Any, Unit](content, { msg =>
                throw new SparkException(s"Unsupported message $message from ${_sender}")
              })
            } catch {
              case NonFatal(e) =>
                context.sendFailure(e)
                // Throw the exception -- this exception will be caught by the safelyCall function.
                // The endpoint's onError function will be called.
                throw e
            }

          case OneWayMessage(_sender, content) =>
            endpoint.receive.applyOrElse[Any, Unit](content, { msg =>
              throw new SparkException(s"Unsupported message $message from ${_sender}")
            })

          case OnStart =>
            endpoint.onStart()
            if (!endpoint.isInstanceOf[ThreadSafeRpcEndpoint]) {
              inbox.synchronized {
                if (!stopped) {
                  enableConcurrent = true
                }
              }
            }

          case OnStop =>
            val activeThreads = inbox.synchronized { inbox.numActiveThreads }
            assert(activeThreads == 1,
              s"There should be only a single active thread but found $activeThreads threads.")
            dispatcher.removeRpcEndpointRef(endpoint)
            endpoint.onStop()
            assert(isEmpty, "OnStop should be the last message")

          case RemoteProcessConnected(remoteAddress) =>
            endpoint.onConnected(remoteAddress)

          case RemoteProcessDisconnected(remoteAddress) =>
            endpoint.onDisconnected(remoteAddress)

          case RemoteProcessConnectionError(cause, remoteAddress) =>
            endpoint.onNetworkError(cause, remoteAddress)
        }
      }

      inbox.synchronized {
        // "enableConcurrent" will be set to false after `onStop` is called, so we should check it
        // every time.
        if (!enableConcurrent && numActiveThreads != 1) {
          // If we are not the only one worker, exit
          numActiveThreads -= 1
          return
        }
        message = messages.poll()
        if (message == null) {
          numActiveThreads -= 1
          return
        }
      }
    }
  }

1.2 post方法。

这个方法就是用来存储待发送的信息,是线程安全的。
在这里插入图片描述

二、Dispatcher类

这个类看名字就知道用来分发message的。

2.1 构造器与成员变量

1.其内部有一个内部类EndpointData,专门用来维护endpoint的名字与对应的inbox对象,如其名字就看成要发送的数据。
2.endpoints用来存储EndpointData对象,当向哪个endpoint发送数据的时候同过该endpoint名字查找即可找到。
3.receivers,一个存储即将需要发送出去的数据的队列。
4.threadpool ,一个线程池默认是操作系统CPU核数的2倍,其专门用来分发信息。

在这里插入图片描述
在这里插入图片描述

2.2 postMessage方法

直接通过endpoint名字从endpoints获取其要存储信息的Inbox,因为这个inbox跟EndpointData对象一一对应。
在这里插入图片描述

2.3 MessageLoop方法

正如代码看到的就是当前线程不停地从blockingQueue里取数据出来,然后丢给对应的inbox进行处理。
在这里插入图片描述

三. outBox类

1.咱们看一下其构造器传参数,主要保存nettyEnv对象以及一个remote rpc地址这与inbox保存endpoint以及其引用不一样。nettyEnv用来创建连接的客户端或者是删除不需要维护的outbox。
2.看里面的成员变量,它持有TransportClient,一个netty的客户端专门用来与远程的endpoint节点进行通信的,这是inbox所没有的。

3.1主要成员变量

在这里插入图片描述

3.2主要的内部类

有两个内部类,都是用来发信息,主要关注sendWith方法,一个有回调函数,一个没有。
在这里插入图片描述
在这里插入图片描述

3.2send方法

当调用的时候先将message添加进list中,然后开始将数据发送出去

在这里插入图片描述

3.2drainOutbox方法

将list里面的信息都往远程节点发送直至排空,核心的两行代码就是从list里面获取message,然后委托message对象下的nettyClient将数据发送到nettyServer端帮处理该信息。
在这里插入图片描述

四. CoarseGrainedExecutorBackend

1.再回到该类,上一篇在写cluster模式提交的时候咱们就看到了这个类的对象在最后被在一个container里启动并等待分发任务。但这次它是以一个endpoint对象的角色进行观察它在干啥。
2.既然是以一个endpoint的对象观察它,就看一下endpoint有哪些方法。它又是干啥的。从该接口注释看:一个为RPC专门定义的类,该类里的成员方法会因为不同类型的message会触发到,且endpoint的声明周期是[构造器->onStart->receive(多次)->onStop]上面看Inbox的时候也看到了,在实例inbox的时候就将一个OnStart 信息add进入了linkedList队列中。后面就调用了该endpoint的onstart方法了。
3.endpoint处了上面声明周期的方法外还有onDisconnected,onConnected等接口方法。
在这里插入图片描述

3.1 onStart()方法

endpoint接收到onStart信号后就开始后去driver的url,然后进行反向注册。
在这里插入图片描述

3.2 receive方法

一旦onstart且注册成功后就开始接收自己的或来自driver端的message类型,然后进行判断走对应的代码分支执行。
1.当下看到的 RegisteredExecutor和后面接收派发的任务的信息LaunchTask(data)类型。
在这里插入图片描述

五.CoarseGrainedSchedulerBackend

就是这么一个粗粒度调度器专门分发任务给各个executor干活的,看一下它实现的接口ExecutorAllocationClient的注释,一个用于与集群通信的客户端目前仅支持yarn模式。
在这里插入图片描述

5.1调度接口

与任务相关的操作方法。
在这里插入图片描述

5.2重要的成员变量

5.2.1executorDataMap

(1)下面用来维护各个executor的列表方便分发task给executor干活
在这里插入图片描述

5.2.2 DriverEndpoint

driver端用于与其他executor通信的内部成员类,是它负责将task分发出去。接下来看一下重要的方法
在这里插入图片描述

5.2.2.1 onStart方法

在启动后每隔一秒钟就调用endpointRef的send方法将一条message发送出去。
在这里插入图片描述

5.2.2.2 recieve方法

根据接收到message类型匹配到后执行对应的分支代码。
在这里插入图片描述

5.2.2.3 分发任务给executor

在这里插入图片描述

5.2.2.4 launchTasks

(1)启动任务,这里也提到到了如果序列化的任务数据字节比特太大,大于默认的128x1024x1024字节就会建议开启广播变量进行序列化传输任务数据。或者说将默认的128这个值调大但不能超过Int.MaxValue/1024/1024否则就抛异常。
(2)一条重要的代码 executorData.executorEndpoint.send(LaunchTask(new SerializableBuffer(serializedTask)))
就是将序列化的任务包装成LaunchTask
在这里插入图片描述
在这里插入图片描述

六 NettyRpcEndpointRef

上面已经看到了它要将LaunchTask类型的信息通过EndpointRef的send方法进行发送出去。我们就看一下这个send的方法

6.1send方法

它又将LaunchTask任务又进一步包装,进行适配enttyEnv的send这个方法,委托它将信息发送出去。
在这里插入图片描述

七 NettyRpcEnv

7.1重要的成员变量

分发器前面也见到了就一般就自己与自己通信,
transport*就是与远程executor通信关联的变量
在这里插入图片描述

7.2 Send方法

正如6.1看到的它就委托当前这个方法将message发出去。
在这里插入图片描述

7.2 postToOutbox方法

将message发送到executor,这里这个message对象就是上面OutboxMessage这个内部类,可以追回3.2的方法看它通过传入的客户端将信息发出去了。
在这里插入图片描述

7.3 executor执行分发过来的task

回到类CoarseGrainedExecutorBackend。看receive方法,然后看关键代码行executor.launchTask这个方法。
在这里插入图片描述
在这里插入图片描述

结尾

1.到此快速过完了一遍executor起来后等待driver调度分发任务,在这个分发任务的过程中,message信息被层层包装进行适配来自不同类的方法。
2.inbox主要处理本地的RPC,outbox主要处理remote RPC的信息。
3.当序列化的task字节大于128x1024x1024字节的时候,建议你要么使用广播变量要播继续调大这个值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值