Spark Core(十六)Executor执行Task的原理与源码分析(二)

  1. 前述
    1. 在上一章节Spark(十五)Executor执行Task的原理与源码分析我们解析了执行Task之前的一些准备工作,但是还没有正真进入Task的执行程序。在上一章节的解析中,在最后Task里的run方法中调用了抽象方法runTask方法,而我们说了,Task是一个抽象类,而runTask方法也是一个抽象方法,所以Task执行的具体逻辑是有Task的子类实现的,实现类Task抽象类的子类有两种,一个是ShuffleMapTask,一个是ResultTask、所以下边我们将对这两个类进行详细的解析,理解Task执行的具体细节。
  2. ShuffleMapTask原理解析:这类的作用是将RDD的每个Partition拆分成多个buckets(存储桶或者存储区)(基于ShuffleDependency中指定的分区)

    1. ShuffleMapTaskrunTask方法:

       //该方法的作用执行Task,然后将结果返回给调度器
       //其中MapStatus封装了块管理器的地址,以及每个reduce的输出大小
       //以便于传递reduce的任务
       override def runTask(context: TaskContext): MapStatus = {
         //记录反序列化RDD的开始时间
          val deserializeStartTime = System.currentTimeMillis()
          //创建一个序列化器
          val ser = SparkEnv.get.closureSerializer.newInstance()
           // 反序列化广播变量来的得到RDD
          val (rdd, dep) = ser.deserialize[(RDD[_], ShuffleDependency[_, _, _])](
            ByteBuffer.wrap(taskBinary.value), Thread.currentThread.getContextClassLoader)
          _executorDeserializeTime = System.currentTimeMillis() - deserializeStartTime
      
          metrics = Some(context.taskMetrics)
          var writer: ShuffleWriter[Any, Any] = null
          try {
            //获取ShuffleManager
            val manager = SparkEnv.get.shuffleManager
            //利用ShuffleManager获取ShuffleWriter,ShuffleWriter的功能就是将Task计算的结果
            //持久化到shuffle文件中,作为子Stage的输入
            writer = manager.getWriter[Any, Any](dep.shuffleHandle, partitionId, context)
            //通过ShuffleWriter将结果进行持久化到shuffle文件中,作为子Stage的输入
            //rdd.iterator(partition, context)这个方法里就会执行我们自己编写的业务逻辑代码
            writer.write(rdd.iterator(partition, context).asInstanceOf[Iterator[_ <: Product2[Any, Any]]])
            //关闭writer,将元数据写入MapStatus中,然后返回
            writer.stop(success = true).get
          } catch {
            case e: Exception =>
              try {
                if (writer != null) {
                  writer.stop(success = false)
                }
              } catch {
                case e: Exception =>
                  log.debug("Could not stop writer", e)
              }
              throw e
          }
        }
    2. RDDiterator方法,

      final def iterator(split: Partition, context: TaskContext): Iterator[T] = {
          //判断存储级别,如果存储不为None,那么就会从缓存中取出Partition
          if (storageLevel != StorageLevel.NONE) {
            SparkEnv.get.cacheManager.getOrCompute(this, split, context, storageLevel)
          } else {
            //Partition没有缓存,就调用这个方法
            computeOrReadCheckpoint(split, context)
          }
      }
    3. RDDcomputeOrReadCheckpoint方法,

      private[spark] def computeOrReadCheckpoint(split: Partition, context: TaskContext): Iterator[T] ={
          if (isCheckpointedAndMaterialized) {
            firstParent[T].iterator(split, context)
          } else {
            //调用RDD的compute方法开始执行Task
            compute(split, context)
          }
      }
    4. MapPartitionsRDDcompute方法

      override def compute(split: Partition, context: TaskContext): Iterator[U] =
          //该方法就是Spark执行了我们自己写的处理逻辑代码
          //f:Spark封装了我们的逻辑代码
          f(context, split.index, firstParent[T].iterator(split, context))
  3. ResultTask runTask原理解析

    1. ResultTaskrunTask方法,因为ResultTask执行的结果就是最终结果,要不返回,要不持久化,所以它的处理逻辑很简单。

      override def runTask(context: TaskContext): U = {
          //记录反序列化RDD的开始时间
          val deserializeStartTime = System.currentTimeMillis()
          /创建一个序列化器
          val ser = SparkEnv.get.closureSerializer.newInstance()
          // 反序列化广播变量来的得到RDD
          val (rdd, func) = ser.deserialize[(RDD[T], (TaskContext, Iterator[T]) => U)](
            ByteBuffer.wrap(taskBinary.value), Thread.currentThread.getContextClassLoader)
          _executorDeserializeTime = System.currentTimeMillis() - deserializeStartTime
      
          metrics = Some(context.taskMetrics)
          //因为ResultTask执行后的结果不会给任何其他的Task用,所以就直接调用rdditerator方法
          //执行我们自己定义的逻辑代码
          func(context, rdd.iterator(partition, context))
        }
    2. RDDiterator方法

      final def iterator(split: Partition, context: TaskContext): Iterator[T] = {
          if (storageLevel != StorageLevel.NONE) {
            SparkEnv.get.cacheManager.getOrCompute(this, split, context, storageLevel)
          } else {
            computeOrReadCheckpoint(split, context)
          }
        }
    3. RDDcomputeOrReadCheckpoint方法,

        private[spark] def computeOrReadCheckpoint(split: Partition, context: TaskContext): Iterator[T] = {
          if (isCheckpointedAndMaterialized) {
            firstParent[T].iterator(split, context)
          } else {
            compute(split, context)
          }
        }
    4. ShuffleRDDcompute方法

        override def compute(split: Partition, context: TaskContext): Iterator[(K, C)] = {
          val dep = dependencies.head.asInstanceOf[ShuffleDependency[K, V, C]]
          SparkEnv.get.shuffleManager.getReader(dep.shuffleHandle, split.index, split.index + 1, context)
            .read()
            .asInstanceOf[Iterator[(K, C)]]
        }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值