spark core源码阅读-Storage shuffle(八)

spark core源码阅读-Storage shuffle(八)

本节主要介绍RDD.aggregateByKey导致的shuffle,分两部分map shuffle,reduce shuffle

一 map shuffle

ShuffleMapTask中Task如何处理rdd.iterator,shuffle中Map端如何根据根据分区把数据写入文件.

主要类简述

  • ShuffleManager
    Driver/Executors创建SparkEnv时创建该类,不同的ShuffleManager对应不同ShuffleWriter,
    通过Driver通过spark.shuffle.manager指定使用策略

    三个重要方法:

    registerShuffle:driver端初始化ShuffleDependency生成
    getWriter:在map任务中生成shuffle后的文件
    getReader:在reduce任务中获取,以从mappers中读取被组合的记录

    分类:

    • (1) HashShuffleManager
      1.2.0版本shuffle方式,有一些缺点,主要是大量小文件,每一个mapper task根据reducer数量创建分区文件,假设有M个Mapper,
      R个Reducer,总共会创建M*R个小文件,如果有46k个Mapper和46k个reducer就会在集群产生2billion的文件
      目前的版本已经做了优化,在mapper端优化,executor中task写同样文件,不过在1.5版本删除了SPARK-9808,
      因为有更好的基于排序的shuffle改进

    优点:

    • 快,不需要排序,不需要维护hash表
    • 没有额外的排序内存消耗
    • 没有IO开销,一次性写硬盘,一次性读硬盘

    缺点:

    • partitions数量多,会产生大量小文件,影响性能
    • 写入文件系统的大量文件导致IO倾向于随机IO,这通常比顺序IO慢100倍

    • (2) SortShuffleManager

    default,在基于排序的shuffle中,rdd iter records将根据其目标分区ID进行排序写入单个map输出文件.
    reducer获取此文件的连续区域以便阅读他们的map输出部分。 在map输出数据太大而不适合缓存的情况下
    排序的输出子集可以被分散到磁盘上,并且这些磁盘上的文件被合并生成最终的输出文件。

  • ShuffleHandle
    registerShuffle,根据不同场景选择不同ShuffleWriter

  • ShuffleWriter

    • HashShuffleManager=>HashShuffleWriter
      过程如图:
      HashShuffleManager.jpg

    • SortShuffleManager
      Manager按照以下顺序,根据不同条件选择ShuffleHandle:

    • UnsafeShuffleWriter(Tungsten中优化项)
      SPARK-7081
      使用特殊高效内存排序ShuffleExternalSorter, 它对压缩记录指针和分区ID数组进行排序,通过在排序阵列中每个记录
      仅使用8个字节的空间,CPU缓存可以更有效地工作
      触发条件:

      • 序列化策略支持如UnsafeRowSerializer,KryoSerializer,能直接在二进制上操作不需要反序列化数据
      • 不需要聚合
      • 分区数不能超过16 million
    • BypassMergeSortShuffleWriter
      HashShuffleWriterSPARK-9808放在该类,在writePartitionedFile方法中合并所有分区文件,这样每个map一个
      output文件,HashShuffleManager2billion的shuffle文件就减少到46k
      触发条件:

      • spark.shuffle.manager=sort
      • “reducers”<“spark.shuffle.sort.bypassMergeThreshold” (默认200)
    • SortShuffleWriter
      过程如图:
      SortShuffleWriter.png
  • ExternalSorter
    通过Partitioner把key分区,在每个分区内排序,为每个分区输出单个分区文件

  • IndexShuffleBlockResolver
    逻辑块与物理文件Mapping,生成数据文件块索引文件

  • PartitionedAppendOnlyMap

    具有以下特征:

    • AppendOnlyMap 内存存储,只能添加
    • WritablePartitionedPairCollection
      • 键值对都有分区信息
      • 支持高效的内存排序iter
      • 支持WritablePartitionedIterator直接以字节形式写入内容
  • Sorter
    TimSort:是结合了合并排序(merge sort)和插入排序(insertion sort)而得出的排序算法

Storage-shuffle.png

主要方法

  • insertAll

    PartitionedAppendOnlyMap.insertAll.png

    迭代器循环处理数据
    内存不足溢出到磁盘

    // Combine values in-memory first using our AppendOnlyMap
    val mergeValue = aggregator.get.mergeValue
    val createCombiner = aggregator.get.createCombiner
    var kv: Product2[K, V] = null
    val update = (hadValue: Boolean, oldValue: C) => {
    if (hadValue) mergeValue(oldValue, kv._2) else createCombiner(kv._2)
    }
    while (records.hasNext) {
    addElementsRead()
    kv = records.next()
    // map=>PartitionedAppendOnlyMap
    map.changeValue((getPartition(kv._1), kv._1), update)
    // 内存不足溢出到磁盘
    maybeSpillCollection(usingMap = true)
    }
  • writePartitionedFile

    将所有添加到ExternalSorter中的数据写入磁盘存储中的文件

writePartitionedFile.png

二 reduce shuffle

看一下ShuffledRDD中的compute

  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)]]
  }
  • BlockStoreShuffleReader

    该方法中:

    • 通过ShuffleBlockFetcherIterator远程获取各个map端相应的分区数据
    • 需要map端合并,combineCombinersByKey,使用ExternalAppendOnlyMap.insertAll数据结构缓存,内存不足溢出文件
    • 需要排序,ExternalSorter.insertAll循环排序
    • sorter.iterator合并数据集(如果有多个溢出文件,合并成一个)
    • 返回CompletionIterator

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值