Spark Shuffle(ExternalSorter)
1、Shuffle流程
spark的shuffle过程如下图所示,和mapreduce中的类似,但在spark2.0及之后的版本中只存在SortShuffleManager而将原来的HashShuffleManager废弃掉(但是shuffleWriter的子类BypassMergeSortShuffleWriter和已经被废弃掉的HashShuffleWriter类似)。这样,每个mapTask在shuffle的sort阶段只会生成一个结果文件,单个文件按照partitionId分成多个region。reducer阶段根据partitionId来fetch对应的region数据。
整个shuffle过程分为两个阶段,write(核心)和read阶段,其中write阶段比较重要的实现类为ExternalSorter(后面会重点分析该类)。

2、Shuffle Write
- BypassMergeSortShuffleWriter -
这种方式是对partition(对应的reduce)数量较少且不需要map-side aggregation的shuffle优化,将每个partition的数据直接写到对应的文件,在所有数据都写入完成后进行一次合并,下面是部分代码:
[BypassMergeSortShuffleWriter]->write
public void write(Iterator<Product2<K, V>> records) throws IOException {
...
partitionWriters = new DiskBlockObjectWriter[numPartitions];
/**
为每个partition创建一个DiskWriter用于写临时文件
**/
for (int i = ; i < numPartitions; i++) {
final Tuple2<TempShuffleBlockId, File> tempShuffleBlockIdPlusFile =
blockManager.diskBlockManager().createTempShuffleBlock();
final File file = tempShuffleBlockIdPlusFile._2();
final BlockId blockId = tempShuffleBlockIdPlusFile._1();
partitionWriters[i] =
blockManager.getDiskWriter(blockId, file, serInstance, fileBufferSize, writeMetrics);
}
...
/**
对每个record用对应的writer进行文件写入操作
**/
while (records.hasNext()) {
final Product2<K, V> record = records.next();
final K key = record._1();
partitionWriters[partitioner.getPartition(key)].write(key, record._2());
}
//flush
for (DiskBlockObjectWriter writer : partitionWriters) {
writer.commitAndClose();
}
/**
构造最终的输出文件实例,其中文件名为(reduceId为0):
"shuffle_" + shuffleId + "_" + mapId + "_" + reduceId
文件所在的local文件夹是根据该文件名的hash值确定。
1、如果运行在yarn上,yarn在启动的时候会根据配置项'LOCAL_DIRS'在本地创建
文件夹
**/
File output = shuffleBlockResolver.getDataFile(shuffleId, mapId);
//在实际结果文件名后加上uuid用于标识文件正在写入,结束后重命名
File tmp = Utils.tempFileWith(output);
try {
//合并每个partition对应的文件到一个文件中
partitionLengths = writePartitionedFile(tmp);
//将每个partition的offset写入index文件方便reduce端fetch数据
shuffleBlockResolver.writeIndexFileAndCommit(shuffleId, mapId, partitionLengths, tmp);
} finally {
if (tmp.exists() && !tmp.delete()) {
logger.error("Error while deleting temp file {}", tmp.getAbsolutePath());
}
}
mapStatus = MapStatus$.MODULE$.apply(blockManager.shuffleServerId(),
partitionLengths);
}
UnsafeShuffleWriter(详见project tungsten)
该writer可将数据序列化后写入到堆外内存,只需要按照partitionid对地址进行排序,整个过程不涉及反序列化。
条件:
1、使用的序列化类需要支持object relocation.目前只能使用kryoSerializer
2、不需要map side aggregate即不能定义aggregator
3、partition数量不能大于支持的上限(2^24)
内存模型:
每条数据地址由一个64位的指针确定,其构成为:[24 bit partition number][13 bit memory page number][27 bit offset in page]
在内存为非8字节对齐的情况下,每个page的容量为227bits=128Mb,page总数为213,因此每个task可操作内存总量为:227*213bits=1Tb,在内存按字节对齐的情况下允许每个page的size有1g(即128*8,实际64位系统的内存都是8字节对齐的)的容量,数据存放在off heap上。在地址中加入partitionID 是为了排序阶段只需要对record的地址排序。
4、Shuffle过程中涉及到的几个参数
- spark.shuffle.sort.bypassMergeThreshold
当partition的数量小于该值并且不需要进行map-side aggregation时使用BypassMergeSortShuffleWriter来进行shuffle的write操作,默认值为200.
[SortShuffleWriter]->shouldBypassMergeSort
def shouldBypassMergeSort(conf: SparkConf, dep: ShuffleDependency[_, _, _]): Boolean = {
if (dep.mapSideCombine) {
require(dep.aggregator.isDefined, "Map-side combine without Aggregator specified!")
false
} else {
val bypassMergeThreshold: Int = conf.getInt("spark.shuffle.sort.bypassMergeThreshold", )
dep.partitioner.numPartitions <= bypassMergeThreshold
}
}```
- *spark.shuffle.compress*、*spark.shuffle.file.buffer*
**[DiskBlockObjectWriter]->open**
def open(): DiskBlockObjectWriter = {
...
/**
'spark.shuffle.compress'-该参数决定是否对写入文件的序列化数据进行压缩。
'spark.shuffle.file.buffer'-设置buffer stream的buffersize,每write
一个byte时会检查当前buffer容量,容量满的时候则会flush到磁盘。该参数值在代码中
会乘以1024转换为字节长度。默认值为'32k',该值太大可能导致内存溢出。
**/
bs = compressStream(new BufferedOutputStream(ts, bufferSize))
...
}```
spark.file.transferTo
决定在使用BypassMergeWriter过程中,最后对文件进行合并时是否使用NIO方式进行file stream的copy。默认为true,在为false的情况下合并文件效率比较低(创建一个大小为8192的字节数组作为buffer,从in stream中读满后写入out stream,单线程读写),版本号为2..32的linux内核在使用NIO方式会产生bug,需要将该参数设置为false。
spark.shuffle.spill.numElementsForceSpillThreshold
在使用UnsafeShuffleWriter时,如果内存中的数据超过这个值则对当前内存数据进行排序并写入磁盘临时文件。
Spark Shuffle(ExternalSorter)的更多相关文章
- Spark Shuffle(一)ShuffleWrite:Executor如何将Shuffle的结果进行归并写到数据文件中去(转载)
转载自:https://blog.csdn.net/raintungli/article/details/70807376 当Executor进行reduce运算的时候,生成运算结果的临时Shuffl ...
- Spark Shuffle(三)Executor是如何fetch shuffle的数据文件(转载)
1. 前言 在前面的博客中讨论了Executor, Driver之间如何汇报Executor生成的Shuffle的数据文件,以及Executor获取到Shuffle的数据文件的分布,那么Executo ...
- Spark Shuffle(二)Executor、Driver之间Shuffle结果消息传递、追踪(转载)
1. 前言 在博客里介绍了ShuffleWrite关于shuffleMapTask如何运行,输出Shuffle结果到Shuffle_shuffleId_mapId_0.data数据文件中,每个exec ...
- Dream_Spark-----Spark 定制版:003~Spark Streaming(三)
Spark 定制版:003~Spark Streaming(三) 本讲内容: a. Spark Streaming Job 架构和运行机制 b. Spark Streaming Job 容错架构和运行 ...
- .Spark Streaming(上)--实时流计算Spark Streaming原理介
Spark入门实战系列--7.Spark Streaming(上)--实时流计算Spark Streaming原理介绍 http://www.cnblogs.com/shishanyuan/p/474 ...
- Spark教程——(11)Spark程序local模式执行、cluster模式执行以及Oozie/Hue执行的设置方式
本地执行Spark SQL程序: package com.fc //import common.util.{phoenixConnectMode, timeUtil} import org.apach ...
- Spark源码分析之Spark Shell(下)
继上次的Spark-shell脚本源码分析,还剩下后面半段.由于上次涉及了不少shell的基本内容,因此就把trap和stty放在这篇来讲述. 上篇回顾:Spark源码分析之Spark Shell(上 ...
- Spark学习之Spark Streaming(9)
Spark学习之Spark Streaming(9) 1. Spark Streaming允许用户使用一套和批处理非常接近的API来编写流式计算应用,这就可以大量重用批处理应用的技术甚至代码. 2. ...
- Spark学习之Spark SQL(8)
Spark学习之Spark SQL(8) 1. Spark用来操作结构化和半结构化数据的接口--Spark SQL. 2. Spark SQL的三大功能 2.1 Spark SQL可以从各种结构化数据 ...
随机推荐
- 详解MathType中如何插入特殊符号
在论文写作中,经常会用到一些特殊符号,MathType公式编辑器支持插入特殊符号,并且数量繁多,可以满足用户的需求.本教程将详解MathType如何插入特殊符号. MathType中插入特殊符号的操作 ...
- angularJs 页面{{xxx}}使用三目运算符
<td>{{::item.sex=='w'?'女':'男'}}</td>,记得引号.也可以不用::,用不用::的区别,自行百度
- NopCommerce的定时任务分析和应用
NOP的定时任务也是群里听群友听说,我很少在WEB端做定时任务,所以尝鲜下,看看效果怎么样. 主要涉及到下面几个类和配置文件配置: web.config <configSections> ...
- SQLServer------如何让标识列重新开始计算
方法: DBCC CHECKIDENT (表名, RESEED, )
- 超全面的JavaWeb笔记day08<Tomcat&Web应用&HTTP协议>
1.常用软件体系结构 BS:浏览器/服务器 CS:客户端/服务器 WEB资源 动态资源 JSP Servlet 静态资源 html 常用服务器 Tomcat Weblogic Resin JBOSS ...
- POJ 3093 Margaritas(Kind of wine) on the River Walk (背包方案统计)
题目 Description One of the more popular activities in San Antonio is to enjoy margaritas in the park ...
- VC++第三方库配置-OpenSpirit 4.2.0 二次开发
在VS中右击项目,点击属性 1.配置属性--常规--输出目录:Windows\VS2010\debug\ 2.配置属性--常规--中间目录:Windows\VS2010\debug\ 3.配置属性-- ...
- android studio如何生成签名文件,以及SHA1和MD5值
一.生成签名文件 1.点击菜单栏中的Build的. 2.弹出窗体,如下图,选中Generate Signed APK,并点击. 3.弹出窗体,如下图. 4.点击Create new…按钮,创建一个签名 ...
- React如何进行事件传参
今天在学习React的es6语法的时候,发现了个有趣的现象,就是this的指向问题.es6的this不同于es5,它在创立函数伊始便已经存在了,而不是像es5一样,睡调用的函数,this指向谁.但是这 ...
- img标签-srcset属性
今天看前辈的代码时,发现img标签有个陌生的srcset属性,如下: 1 <img class="Avatar" src="https://pic3.zhimg.c ...