1.Shuffle Write 和Shuffle Read具体发生在哪里

2.哪里用到了Partitioner

3.何为mapSideCombine

4.何时进行排序

之前已经看过spark shuffle源码了,现在总结一下一些之前没有理解的小知识点,作为一个总结。

用户自定义的Partitioner存到了哪里?

假设用户在调用reduceByKey时,传递了一个自定义的Partitioner,那么,这个Partitioner会被保存到ShuffleRDD的ShuffleDependency中。在进行Shuffle Write时,会使用这个Partitioner来对finalRDD.iterator(partition)的计算结果shuffle到不同的Bucket中。

何为mapSideCombine

reduceByKey默认是开启了mapSideCombine的,在进行shuffle write时会进行本地聚合,在shuffle read时,也会合并一下。举一个例子更好:

shuffle write阶段:

partition0:[(hello,1),(hello,1)]

partition1:[(hello,1),(word,1),(word,1)]

mapSideCombine后:

partition0:[(hello,2)]

partition1:[(hello,1),(word,2)]

hash shuffle后:

[(hello,2),(hello,1)]

[(word,2)]

hash read阶段:

[(hello,3)]

[(word,2)]

何时排序

排序操作发生在shuffle read 阶段。在shuffle read 进行完mapSideCombine之后,就开始进行排序了。

reduceByKey做了什么?

假设我们对rdd1调用了reduceByKey,那么最终的RDD依赖关系如下:rdd1->ShuffleRDD。rdd1.reduceByKey中,会做如下非常重要的事情:创建ShuffleRDD,在创建ShuffleRDD的过程中最最最重要的就是会创建ShuffleDependency,这个ShuffleDependency中有Aggregator,Partitioner,Ordering,parentRDD,mapSideCombine等重要的信息。为什么说ShuffleDependency非常重要,因为他是沟通Shuffle Writer和Shuffle Reader的一个重要桥梁。

Shuffle Write

Shuffle Write 发生在ShuffleMapTask.runTask中。首先反序列出rdd1和那个ShuffleDependency:(rdd1,dep),然后调用rdd1.iterator(partition)获取计算结果,再对计算结果进行ShuffleWriter,代码如下:

override def runTask(context: TaskContext): MapStatus = {
// Deserialize the RDD using the broadcast variable.
val deserializeStartTime = System.currentTimeMillis()
val ser = SparkEnv.get.closureSerializer.newInstance()
//统计反序列化rdd和shuffleDependency的时间
val (rdd, dep) = ser.deserialize[(RDD[_], ShuffleDependency[_, _, _])](
ByteBuffer.wrap(taskBinary.value), Thread.currentThread.getContextClassLoader)
_executorDeserializeTime = System.currentTimeMillis() - deserializeStartTime metrics = Some(context.taskMetrics)
var writer: ShuffleWriter[Any, Any] = null
try {
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]]])
return writer.stop(success = true).get
} catch {
case e: Exception =>
try {
if (writer != null) {
writer.stop(success = false)
}
} catch {
case e: Exception =>
log.debug("Could not stop writer", e)
}
throw e
}
}

我们以HashSuffleWriter为例,在其write(),他就会用到mapSideCombine和Partitioner。如下:

/** Write a bunch of records to this task's output */
override def write(records: Iterator[Product2[K, V]]): Unit = {
val iter = if (dep.aggregator.isDefined) {
if (dep.mapSideCombine) {
dep.aggregator.get.combineValuesByKey(records, context)
} else {
records
}
} else {
require(!dep.mapSideCombine, "Map-side combine without Aggregator specified!")
records
} for (elem <- iter) {
val bucketId = dep.partitioner.getPartition(elem._1)
shuffle.writers(bucketId).write(elem._1, elem._2)
}
}

Shuffle Read

shuffle Read发生在ShuffleRDD的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)]]
}

下面是HashShuffleReader的read():

  /** Read the combined key-values for this reduce task */
override def read(): Iterator[Product2[K, C]] = {
val ser = Serializer.getSerializer(dep.serializer)
val iter = BlockStoreShuffleFetcher.fetch(handle.shuffleId, startPartition, context, ser) val aggregatedIter: Iterator[Product2[K, C]] = if (dep.aggregator.isDefined) {
if (dep.mapSideCombine) {
new InterruptibleIterator(context, dep.aggregator.get.combineCombinersByKey(iter, context))
} else {
new InterruptibleIterator(context, dep.aggregator.get.combineValuesByKey(iter, context))
}
} else {
require(!dep.mapSideCombine, "Map-side combine without Aggregator specified!") // Convert the Product2s to pairs since this is what downstream RDDs currently expect
iter.asInstanceOf[Iterator[Product2[K, C]]].map(pair => (pair._1, pair._2))
} // Sort the output if there is a sort ordering defined.
dep.keyOrdering match {
case Some(keyOrd: Ordering[K]) =>
// Create an ExternalSorter to sort the data. Note that if spark.shuffle.spill is disabled,
// the ExternalSorter won't spill to disk.
val sorter = new ExternalSorter[K, C, C](ordering = Some(keyOrd), serializer = Some(ser))
sorter.insertAll(aggregatedIter)
context.taskMetrics.incMemoryBytesSpilled(sorter.memoryBytesSpilled)
context.taskMetrics.incDiskBytesSpilled(sorter.diskBytesSpilled)
sorter.iterator
case None =>
aggregatedIter
}
}

spark shuffle 相关细节整理的更多相关文章

  1. Chrome浏览器相关细节整理

    一.上传文件卡死 可能时由于输入法的原因导致上传文件浏览器卡死.将输入法改为英文模式再操作上传文件就不会卡死了.

  2. Spark Shuffle的技术演进

      在Spark或Hadoop MapReduce的分布式计算框架中,数据被按照key分成一块一块的分区,打散分布在集群中各个节点的物理存储或内存空间中,每个计算任务一次处理一个分区,但map端和re ...

  3. Spark 性能相关参数配置详解-shuffle篇

    随着Spark的逐渐成熟完善, 越来越多的可配置参数被添加到Spark中来, 在Spark的官方文档http://spark.apache.org/docs/latest/configuration. ...

  4. Spark 性能相关參数配置具体解释-shuffle篇

    作者:刘旭晖 Raymond 转载请注明出处 Email:colorant at 163.com BLOG:http://blog.csdn.net/colorant/ 随着Spark的逐渐成熟完好, ...

  5. spark shuffle:分区原理及相关的疑问

    一.分区原理 1.为什么要分区?(这个借用别人的一段话来阐述.) 为了减少网络传输,需要增加cpu计算负载.数据分区,在分布式集群里,网络通信的代价很大,减少网络传输可以极大提升性能.mapreduc ...

  6. spark shuffle写操作之SortShuffleWriter

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

  7. Spark面试相关

    Spark Core面试篇01 随着Spark技术在企业中应用越来越广泛,Spark成为大数据开发必须掌握的技能.前期分享了很多关于Spark的学习视频和文章,为了进一步巩固和掌握Spark,在原有s ...

  8. Spark Shuffle(一)ShuffleWrite:Executor如何将Shuffle的结果进行归并写到数据文件中去(转载)

    转载自:https://blog.csdn.net/raintungli/article/details/70807376 当Executor进行reduce运算的时候,生成运算结果的临时Shuffl ...

  9. Spark 性能相关参数配置详解-任务调度篇

    随着Spark的逐渐成熟完善, 越来越多的可配置参数被添加到Spark中来, 本文试图通过阐述这其中部分参数的工作原理和配置思路, 和大家一起探讨一下如何根据实际场合对Spark进行配置优化. 由于篇 ...

随机推荐

  1. ubuntu 15.10 安装swift开发环境 2016/4/17

    ubuntu 15.10 64位 下载地址 https://swift.org/download/#using-downloads 1.首先在ubuntu终端上 (ctl+alt+t打开) 下载cla ...

  2. 重视blog备份——兼记我与CSDN的爱恨情仇

    痛定思痛,终于决定--逐渐备份.迁移CSDN博客到"博客园". 缘起 前几年比较喜欢逛csdn的bbs,虽然之前在cnblogs也注册了账号,但一直用CSDN博客比较多.本来一直用 ...

  3. MongoDB学习笔记

    MongoDB的学习目标(v.3.4.0) 1.MongoDB的概念,非关系型数据库NOSQL 2.学会MongoDB的搭建 3.熟悉MongoDB使用 最基本的文档的读写更新删除 各种不同类型的索引 ...

  4. 【JavaScript】--重点解析之跨域请求

    JSON JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式. JSON是用字符串来表示Javascript对象,例如可以在django中发送一个JSON格式 ...

  5. c# 保存数据到txt (追加)

    StringBuilder sb = new StringBuilder(); sb.AppendLine(DateTime.Now.ToString("yyyy-MM-dd hh:mm:s ...

  6. 【笔记】js的内存字节转化

    function convertSize(size) {                if(!size) {                     return '0 Bytes';       ...

  7. $\mathscr{F}$类

    $\mathscr{F}$类:在单位元盘$B(0,1)$中满足$$f(0)=0,f'(0)=1$$ 的双全纯函数的全体.

  8. SQL中TOP,LIMIT,ROWNUM的用法

    SQL SERVER/MS Access的Select Top的用法: Select TOP number|percent table_columname FROM tablename MySQL/O ...

  9. 鱼搜_鱼搜官网_鱼搜搜索_http://www.7yusou.com

    收集了N多视频小站,然后花了3天时间弄了一个鱼搜搜索网站.欢迎大家访问哟. http://www.7yusou.com

  10. HDU5887 Herbs Gathering(2016青岛网络赛 搜索 剪枝)

    背包问题,由于数据大不容易dp,改为剪枝,先按性价比排序,若剩下的背包空间都以最高性价比选时不会比已找到的最优解更好时则剪枝,即 if(val + (LD)pk[d].val / (LD)pk[d]. ...