这篇文章会详细介绍,Sort Based Shuffle Write 阶段是如何进行落磁盘的

流程分析

入口处:

org.apache.spark.scheduler.ShuffleMapTask.runTask

runTask对应的代码为:

val manager = SparkEnv.get.shuffleManager
writer = manager.getWriter[Any, Any](
dep.shuffleHandle,
partitionId,
context)
writer.write(rdd.iterator(partition, context).asInstanceOf[Iterator[_ <: Product2[Any, Any]]])
writer.stop(success = true).get

这里manager 拿到的是

org.apache.spark.shuffle.sort.SortShuffleWriter

我们看他是如何拿到可以写磁盘的那个sorter的。我们分析的线路假设需要做mapSideCombine

sorter = if (dep.mapSideCombine) {
require(dep.aggregator.isDefined, "Map-side combine without Aggregator specified!")
new ExternalSorter[K, V, C](
dep.aggregator,
Some(dep.partitioner),
dep.keyOrdering, de.serializer)

接着将map的输出放到sorter当中:

sorter.insertAll(records)

其中insertAll 的流程是这样的:

while (records.hasNext) {
addElementsRead() kv = records.next()
map.changeValue((getPartition(kv._1), kv._1), update)
maybeSpillCollection(usingMap = true)}

里面的map 其实就是PartitionedAppendOnlyMap,这个是全内存的一个结构。当把这个写满了,才会触发spill操作。你可以看到maybeSpillCollection在PartitionedAppendOnlyMap每次更新后都会被调用。

一旦发生spill后,产生的文件名称是:

    "temp_shuffle_" + id

逻辑在这:

val (blockId, file) = diskBlockManager.createTempShuffleBlock() 

  def createTempShuffleBlock(): (TempShuffleBlockId, File) = {
var blockId = new TempShuffleBlockId(UUID.randomUUID())
while (getFile(blockId).exists()) {
blockId = new TempShuffleBlockId(UUID.randomUUID())
}
(blockId, getFile(blockId))
}

产生的所有 spill文件被被记录在一个数组里:

  private val spills = new ArrayBuffer[SpilledFile]

迭代完一个task对应的partition数据后,会做merge操作,把磁盘上的spill文件和内存的,迭代处理,得到一个新的iterator,这个iterator的元素会是这个样子的:

(p, mergeWithAggregation(
iterators,
aggregator.get.mergeCombiners, keyComparator,
ordering.isDefined))

其中p 是reduce 对应的partitionId, p对应的所有数据都会在其对应的iterator中。

接着会获得最后的输出文件名:

val outputFile = shuffleBlockResolver.getDataFile(dep.shuffleId, mapId)

文件名格式会是这样的:

 "shuffle_" + shuffleId + "_" + mapId + "_" + reduceId + ".data"

其中reduceId 是一个固定值NOOP_REDUCE_ID,默认为0。

然后开始真实写入文件

  val partitionLengths = sorter.writePartitionedFile(
blockId,
context,
outputFile)

写入文件的过程过程是这样的:

for ((id, elements) <- this.partitionedIterator) {
if (elements.hasNext) { val writer = blockManager.getDiskWriter(blockId,
outputFile,
serInstance,
fileBufferSize,
context.taskMetrics.shuffleWriteMetrics.get) for (elem <- elements) {
writer.write(elem._1, elem._2)
} writer.commitAndClose()
val segment = writer.fileSegment()
lengths(id) = segment.length
}
}
刚刚我们说了,这个 this.partitionedIterator 其实内部元素是reduce partitionID -> 实际record 的 iterator,所以它其实是顺序写每个分区的记录,写完形成一个fileSegment,并且记录偏移量。这样后续每个的reduce就可以根据偏移量拿到自己需要的数据。对应的文件名,前面也提到了,是:
"shuffle_" + shuffleId + "_" + mapId + "_" + NOOP_REDUCE_ID + ".data"

刚刚我们说偏移量,其实是存在内存里的,所以接着要持久化,通过下面的writeIndexFile来完成:

shuffleBlockResolver.writeIndexFile(
dep.shuffleId,
mapId,
partitionLengths)

具体的文件名是:

  "shuffle_" + shuffleId + "_" + mapId + "_" + NOOP_REDUCE_ID + ".index"

至此,一个task的写入操作完成,对应一个文件。

最终结论

所以最后的结论是,一个Executor 最终对应的文件数应该是:

MapNum (注:不包含index文件)

同时持有并且会进行写入的文件数最多为::

 CoreNum

Spark Shuffle Write阶段磁盘文件分析的更多相关文章

  1. Spark Shuffle之Sort Shuffle

    源文件放在github,随着理解的深入,不断更新,如有谬误之处,欢迎指正.原文链接https://github.com/jacksu/utils4s/blob/master/spark-knowled ...

  2. spark shuffle

    Spark Shuffle 1. Shuffle相关 当Map的输出结果要被Reduce使用时,输出结果需要按key哈希,并且分发到每一个Reducer上去,这个过程就是shuffle.由于shuff ...

  3. spark shuffle写操作之SortShuffleWriter

    提出问题 1. spark shuffle的预聚合操作是如何做的,其中底层的数据结构是什么?在数据写入到内存中有预聚合,在读溢出文件合并到最终的文件时是否也有预聚合操作? 2. shuffle数据的排 ...

  4. Spark Shuffle机制详细源码解析

    Shuffle过程主要分为Shuffle write和Shuffle read两个阶段,2.0版本之后hash shuffle被删除,只保留sort shuffle,下面结合代码分析: 1.Shuff ...

  5. Spark Shuffle原理、Shuffle操作问题解决和参数调优

    摘要: 1 shuffle原理 1.1 mapreduce的shuffle原理 1.1.1 map task端操作 1.1.2 reduce task端操作 1.2 spark现在的SortShuff ...

  6. MapReduce Shuffle原理 与 Spark Shuffle原理

    MapReduce的Shuffle过程介绍 Shuffle的本义是洗牌.混洗,把一组有一定规则的数据尽量转换成一组无规则的数据,越随机越好.MapReduce中的Shuffle更像是洗牌的逆过程,把一 ...

  7. Spark Shuffle实现

    Apache Spark探秘:Spark Shuffle实现 http://dongxicheng.org/framework-on-yarn/apache-spark-shuffle-details ...

  8. Apache 流框架 Flink,Spark Streaming,Storm对比分析(一)

    本文由  网易云发布. 1.Flink架构及特性分析 Flink是个相当早的项目,开始于2008年,但只在最近才得到注意.Flink是原生的流处理系统,提供high level的API.Flink也提 ...

  9. Spark中的Spark Shuffle详解

    Shuffle简介 Shuffle描述着数据从map task输出到reduce task输入的这段过程.shuffle是连接Map和Reduce之间的桥梁,Map的输出要用到Reduce中必须经过s ...

随机推荐

  1. 向Windows内核驱动传递用户层定义的事件Event,并响应内核层的通知

    完整的程序在下载:http://download.csdn.net/detail/dijkstar/7913249 用户层创建的事件Event是一个Handle句柄,和内核中的创建的内核模式下的KEV ...

  2. sklearn特征抽取

    特征抽取sklearn.feature_extraction 模块提供了从原始数据如文本,图像等众抽取能够被机器学习算法直接处理的特征向量. 1.特征抽取方法之 Loading Features fr ...

  3. 题目1010:A + B(字符串转数字)

    题目链接:http://ac.jobdu.com/problem.php?pid=1010 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...

  4. 压力测试工具JMeter入门教程<转>

    1.Jmeter 概要描叙 jmeter 是一款专门用于功能测试和压力测试的轻量级测试开发平台.多数情况下是用作压力测试,该测试工具在阿里巴巴有着广泛的使用,估计是不要钱吧,哈哈,功能上来说,整个平台 ...

  5. 去除select边框和三角-----appearance:none

    今天发现一个比较有意思的属性,appearance:none 可能有朋友不认识,但是有一个标签你肯定认识:select. 这个标签的样式是这样的: 一般情况下,我们所使用的border:0; 去除边框 ...

  6. 简易扩展Visual Studio UnitTesting支持TestMethodCase

    NUnit的TestCaseAttribute可以简化大量的测试参数输入用例的编写,如果基于Visual Studio Unit Test Project开发则默认没有类似的功能,看一段对比代码: p ...

  7. Facebook Cache Token Issue

    https://developers.facebook.com/docs/ios/token-caching-ios-sdk/ What's session? https://developers.f ...

  8. AFNetWork 简单实用demo

    NSString *postUrl = @"http://www.huway.com/api_index?module=event&action=topads"; NSDi ...

  9. 经典把妹桥段:Flower dance开头对话

    听到一首很赞的钢琴曲,Flower Dance,其开头有一段英文对话,如下: Lucy:"They serve the purpose of changing hydrogen into b ...

  10. iOS - 指定UIView的某几个角为圆角

    如果需要将UIView的4个角全部都为圆角,做法相当简单,只需设置其Layer的cornerRadius属性即可(项目需要使用QuartzCore框架).而若要指定某几个角(小于4)为圆角而别的不变时 ...