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 } }
剛剛我們說了,這個 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
作者:祝威廉
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4662/viewspace-2818600/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【Spark篇】---Spark中Shuffle檔案的定址Spark
- Spark的Shuffle總結分析Spark
- Spark shuffle調優Spark
- Spark Shuffle實現Spark
- spark Shuffle相關Spark
- Spark學習——排序ShuffleSpark排序
- Spark開發-Shuffle優化Spark優化
- Spark 效能調優--開發階段Spark
- Spark面試題(八)——Spark的Shuffle配置調優Spark面試題
- 【Spark篇】---Spark中Shuffle機制,SparkShuffle和SortShuffleSpark
- Spark原始碼解析之Shuffle WriterSpark原始碼
- Spark的兩種核心Shuffle詳解Spark
- Spark-Shuffle過程概要參考Spark
- Spark 效能調優--Shuffle調優 SortShuffleManagerSpark
- 簡要MR與Spark在Shuffle區別Spark
- Spark Shuffle機制詳細原始碼解析Spark原始碼
- Spark中shuffle的觸發和排程Spark
- 分析專案管理執行階段有什麼技巧專案管理
- XLOG段檔案跳號現象分析
- 【Spark篇】---Spark中記憶體管理和Shuffle引數調優Spark記憶體
- Spark 原始碼系列(六)Shuffle 的過程解析Spark原始碼
- 22【線上日誌分析】之專案第二階段概述
- 最新拓薪Java高階階段及ERP實戰專案(階段三)Java
- Macbook磁碟系統結構/檔案/目錄介紹分析Mac
- Spark SQL原始碼解析(四)Optimization和Physical Planning階段解析SparkSQL原始碼
- Spark SQL原始碼解析(五)SparkPlan準備和執行階段SparkSQL原始碼
- 【大資料學習日記】Spark之shuffle調優大資料Spark
- 死磕Spring之IoC篇 - BeanDefinition 的解析階段(XML 檔案)SpringBeanXML
- Spark Streaming監聽HDFS檔案(Spark-shell)Spark
- 第三階段專案總結
- IT專案管理-計劃階段(轉)專案管理
- spark叢集的配置檔案Spark
- Spark基礎-Scala檔案操作Spark
- spark直接讀取本地檔案系統的檔案Spark
- sort-based shuffle的核心:org.apache.spark.util.collection.ExternalSorterApacheSpark
- 死磕Spring之IoC篇 - BeanDefinition 的載入階段(XML 檔案)SpringBeanXML
- Guava 原始碼分析(Cache 原理【二階段】)Guava原始碼
- MapReduce —— MapTask階段原始碼分析(Input環節)APT原始碼