Spark Shuffle Write阶段磁盘文件分析
这篇文章会详细介绍,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
}
}
"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阶段磁盘文件分析的更多相关文章
- Spark Shuffle之Sort Shuffle
源文件放在github,随着理解的深入,不断更新,如有谬误之处,欢迎指正.原文链接https://github.com/jacksu/utils4s/blob/master/spark-knowled ...
- spark shuffle
Spark Shuffle 1. Shuffle相关 当Map的输出结果要被Reduce使用时,输出结果需要按key哈希,并且分发到每一个Reducer上去,这个过程就是shuffle.由于shuff ...
- spark shuffle写操作之SortShuffleWriter
提出问题 1. spark shuffle的预聚合操作是如何做的,其中底层的数据结构是什么?在数据写入到内存中有预聚合,在读溢出文件合并到最终的文件时是否也有预聚合操作? 2. shuffle数据的排 ...
- Spark Shuffle机制详细源码解析
Shuffle过程主要分为Shuffle write和Shuffle read两个阶段,2.0版本之后hash shuffle被删除,只保留sort shuffle,下面结合代码分析: 1.Shuff ...
- Spark Shuffle原理、Shuffle操作问题解决和参数调优
摘要: 1 shuffle原理 1.1 mapreduce的shuffle原理 1.1.1 map task端操作 1.1.2 reduce task端操作 1.2 spark现在的SortShuff ...
- MapReduce Shuffle原理 与 Spark Shuffle原理
MapReduce的Shuffle过程介绍 Shuffle的本义是洗牌.混洗,把一组有一定规则的数据尽量转换成一组无规则的数据,越随机越好.MapReduce中的Shuffle更像是洗牌的逆过程,把一 ...
- Spark Shuffle实现
Apache Spark探秘:Spark Shuffle实现 http://dongxicheng.org/framework-on-yarn/apache-spark-shuffle-details ...
- Apache 流框架 Flink,Spark Streaming,Storm对比分析(一)
本文由 网易云发布. 1.Flink架构及特性分析 Flink是个相当早的项目,开始于2008年,但只在最近才得到注意.Flink是原生的流处理系统,提供high level的API.Flink也提 ...
- Spark中的Spark Shuffle详解
Shuffle简介 Shuffle描述着数据从map task输出到reduce task输入的这段过程.shuffle是连接Map和Reduce之间的桥梁,Map的输出要用到Reduce中必须经过s ...
随机推荐
- 向Windows内核驱动传递用户层定义的事件Event,并响应内核层的通知
完整的程序在下载:http://download.csdn.net/detail/dijkstar/7913249 用户层创建的事件Event是一个Handle句柄,和内核中的创建的内核模式下的KEV ...
- sklearn特征抽取
特征抽取sklearn.feature_extraction 模块提供了从原始数据如文本,图像等众抽取能够被机器学习算法直接处理的特征向量. 1.特征抽取方法之 Loading Features fr ...
- 题目1010:A + B(字符串转数字)
题目链接:http://ac.jobdu.com/problem.php?pid=1010 详解链接:https://github.com/zpfbuaa/JobduInCPlusPlus 参考代码: ...
- 压力测试工具JMeter入门教程<转>
1.Jmeter 概要描叙 jmeter 是一款专门用于功能测试和压力测试的轻量级测试开发平台.多数情况下是用作压力测试,该测试工具在阿里巴巴有着广泛的使用,估计是不要钱吧,哈哈,功能上来说,整个平台 ...
- 去除select边框和三角-----appearance:none
今天发现一个比较有意思的属性,appearance:none 可能有朋友不认识,但是有一个标签你肯定认识:select. 这个标签的样式是这样的: 一般情况下,我们所使用的border:0; 去除边框 ...
- 简易扩展Visual Studio UnitTesting支持TestMethodCase
NUnit的TestCaseAttribute可以简化大量的测试参数输入用例的编写,如果基于Visual Studio Unit Test Project开发则默认没有类似的功能,看一段对比代码: p ...
- Facebook Cache Token Issue
https://developers.facebook.com/docs/ios/token-caching-ios-sdk/ What's session? https://developers.f ...
- AFNetWork 简单实用demo
NSString *postUrl = @"http://www.huway.com/api_index?module=event&action=topads"; NSDi ...
- 经典把妹桥段:Flower dance开头对话
听到一首很赞的钢琴曲,Flower Dance,其开头有一段英文对话,如下: Lucy:"They serve the purpose of changing hydrogen into b ...
- iOS - 指定UIView的某几个角为圆角
如果需要将UIView的4个角全部都为圆角,做法相当简单,只需设置其Layer的cornerRadius属性即可(项目需要使用QuartzCore框架).而若要指定某几个角(小于4)为圆角而别的不变时 ...