ShuffleManager负责管理本地以及远程的block数据的shuffle操作。

ShffuleManager的创建是在SparkEnv中。

    // Let the user specify short names for shuffle managers
val shortShuffleMgrNames = Map(
"sort" -> classOf[org.apache.spark.shuffle.sort.SortShuffleManager].getName,
"tungsten-sort" -> classOf[org.apache.spark.shuffle.sort.SortShuffleManager].getName)
val shuffleMgrName = conf.get("spark.shuffle.manager", "sort")
val shuffleMgrClass = shortShuffleMgrNames.getOrElse(shuffleMgrName.toLowerCase, shuffleMgrName)
//通过反射创建ShuffleManager
val shuffleManager = instantiateClass[ShuffleManager](shuffleMgrClass)

2.1.6.1、在本人的spark版本中(2.1.1)只有SortShuffleManger, 在spark1.2之前还有HashShuffleManager, 已经被移除了。

在Spark的版本的发展,ShuffleManager在不断迭代,变得越来越先进。

在Spark 1.2以前,默认的shuffle计算引擎是HashShuffleManager。该ShuffleManager而HashShuffleManager有着一个非常严重的弊端,就是会产生大量的中间磁盘文件,进而由大量的磁盘IO操作影响了性能。因此在Spark 1.2以后的版本中,默认的ShuffleManager改成了SortShuffleManager。SortShuffleManager相较于HashShuffleManager来说,有了一定的改进。主要就在于,每个Task在进行shuffle操作时,虽然也会产生较多的临时磁盘文件,但是最后会将所有的临时文件合并(merge)成一个磁盘文件,因此每个Task就只有一个磁盘文件。在下一个stage的shuffle read task拉取自己的数据时,只要根据索引读取每个磁盘文件中的部分数据即可。

接下来看看SortShuffleManger功能

注册Shuffle

通过manager注册shuffle,  同时获取一个handle用于发送任务

  /**
* 注册Shuffle
* Register a shuffle with the manager and obtain a handle for it to pass to tasks.
*/
override def registerShuffle[K, V, C](
shuffleId: Int,
numMaps: Int,
dependency: ShuffleDependency[K, V, C]): ShuffleHandle = { //创建handle
if (SortShuffleWriter.shouldBypassMergeSort(SparkEnv.get.conf, dependency)) {
// If there are fewer than spark.shuffle.sort.bypassMergeThreshold partitions and we don't
// need map-side aggregation, then write numPartitions files directly and just concatenate
// them at the end. This avoids doing serialization and deserialization twice to merge
// together the spilled files, which would happen with the normal code path.
// The downside is having multiple files open at a time and thus more memory allocated to buffers. // by pass handle
new BypassMergeSortShuffleHandle[K, V](
shuffleId, numMaps, dependency.asInstanceOf[ShuffleDependency[K, V, V]])
} else if (SortShuffleManager.canUseSerializedShuffle(dependency)) {
// Otherwise, try to buffer map outputs in a serialized form, since this is more efficient:
// 序列化shuffle handle
new SerializedShuffleHandle[K, V](
shuffleId, numMaps, dependency.asInstanceOf[ShuffleDependency[K, V, V]])
} else {
// Otherwise, buffer map outputs in a deserialized form:
// 剩下就是 未序列化格式
new BaseShuffleHandle(shuffleId, numMaps, dependency)
}
}

有三种Handle :  确定使用哪种shuffle path

BypassMergeSortShuffleHandle

SerializedShuffleHandle

BaseShuffleHandle

移除shuffle

  通过ShuffleBlockResolver持有的blockManager.diskBlockManager定位到数据文件和索引文件, 然后删除

  /** Remove a shuffle's metadata from the ShuffleManager. */
override def unregisterShuffle(shuffleId: Int): Boolean = {
Option(numMapsForShuffle.remove(shuffleId)).foreach { numMaps =>
(0 until numMaps).foreach { mapId =>
shuffleBlockResolver.removeDataByMap(shuffleId, mapId)
}
}
true
}

getWriter

  根据给定的partition,获取一个ShuffleWriter, 在executor上被map task调用

  override def getWriter[K, V](
handle: ShuffleHandle,
mapId: Int,
context: TaskContext): ShuffleWriter[K, V] = { //向numMapsForShuffle中添加新的shuffleId,
numMapsForShuffle.putIfAbsent(
handle.shuffleId, handle.asInstanceOf[BaseShuffleHandle[_, _, _]].numMaps) //SparkEnv
val env = SparkEnv.get //根据ShuffleHandle匹配对应的ShuffleWriter
handle match {
case unsafeShuffleHandle: SerializedShuffleHandle[K @unchecked, V @unchecked] =>
new UnsafeShuffleWriter(
env.blockManager,
shuffleBlockResolver.asInstanceOf[IndexShuffleBlockResolver],
context.taskMemoryManager(),
unsafeShuffleHandle,
mapId,
context,
env.conf)
case bypassMergeSortHandle: BypassMergeSortShuffleHandle[K @unchecked, V @unchecked] =>
new BypassMergeSortShuffleWriter(
env.blockManager,
shuffleBlockResolver.asInstanceOf[IndexShuffleBlockResolver],
bypassMergeSortHandle,
mapId,
context,
env.conf)
case other: BaseShuffleHandle[K @unchecked, V @unchecked, _] =>
new SortShuffleWriter(shuffleBlockResolver, other, mapId, context)
}
}

getReader

  创建一个BlockStoreShuffleManager 读取一个范围partition的数据, 在executor上被reduce task调用

  /**
* Get a reader for a range of reduce partitions (startPartition to endPartition-1, inclusive).
* Called on executors by reduce tasks.
*/
override def getReader[K, C](
handle: ShuffleHandle,
startPartition: Int,
endPartition: Int,
context: TaskContext): ShuffleReader[K, C] = {
new BlockStoreShuffleReader(
handle.asInstanceOf[BaseShuffleHandle[K, _, C]], startPartition, endPartition, context)
}

2.1.6、SparkEnv中创建ShuffleManager的更多相关文章

  1. 2.1.5、SparkEnv中创建MapOutputTracker

    SparkEnv中创建MapOutputTracker def registerOrLookupEndpoint( name: String, endpointCreator: => RpcEn ...

  2. 2.1.4、SparkEnv中创建BroadcastManager

    Broadcast是分布式的数据共享,由BroadcastManager负责管理其创建或销毁.Broadcast一般用于处理共享的配置文件.通用Dataset.常用数据结构 通过SparkContex ...

  3. In-Memory:在内存中创建临时表和表变量

    在Disk-Base数据库中,由于临时表和表变量的数据存储在tempdb中,如果系统频繁地创建和更新临时表和表变量,大量的IO操作集中在tempdb中,tempdb很可能成为系统性能的瓶颈.在SQL ...

  4. 【初学者指南】在ASP.NET MVC 5中创建GridView

    介绍 在这篇文章中,我们将会学习如何在 ASP.NET MVC 中创建一个 gridview,就像 ASP.NET Web 表单中的 gridview 一样.服务器端和客户端有许多可用的第三方库,这些 ...

  5. SQL Server 在多个数据库中创建同一个存储过程(Create Same Stored Procedure in All Databases)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 遇到的问题(Problems) 实现代码(SQL Codes) 方法一:拼接SQL: 方法二: ...

  6. SAP CRM 在Web UI中创建搜索帮助

    多数情况下,在Web UI为一个特定的字段提供搜索帮助需要在事务SE11中创建搜索帮助. (注:也可以通过在SE24中创建一个类并实现实现IF_BSP_WD_CUSTOM_F4_CALLBACK接口来 ...

  7. 详解Linux交互式shell脚本中创建对话框实例教程_linux服务器

    本教程我们通过实现来讲讲Linux交互式shell脚本中创建各种各样对话框,对话框在Linux中可以友好的提示操作者,感兴趣的朋友可以参考学习一下. 当你在终端环境下安装新的软件时,你可以经常看到信息 ...

  8. 如何在ARM中创建Express Route

    很早之前就想试试Azure的express route,但是一直没有找到合适的机会,正好有个客户需要上express route,所以最近先自己研究研究,防止在做poc的时候耗费更多时间,本次场景我们 ...

  9. 在powerdesigner中创建物理数据模型

    物理数据模型(PDM)是以常用的DBMS(数据库管理系统)理论为基础,将CDM/LDM中所建立的现实世界模型生成相应的DBMS的SQL语言脚本.PDM叙述数据库的物理实现,是对真实数据库的描述 PDM ...

随机推荐

  1. SPOJ - QMAX3VN (4350) splay

    SPOJ - QMAX3VN 一个动态的序列 ,在线询问某个区间的最大值.关于静态序列的区间最值问题,用ST表解决,参考POJ 3264 乍一看上去 splay可以轻松解决.书上说可以用块状链表解决, ...

  2. error: undefined reference to 'property_set (转载)

    转自:http://blog.csdn.net/u011589606/article/details/23474241 in the cpp file, please include #include ...

  3. 对于Mobile模块化的概念认知(小白)

    最近刚刚学习了Mobile的一些基础知识,把它整理一下方便自己的学习 那什么是Mobile呢? 自己的理解是将一个项目中共同的部分抽出来,这样就形成了Mobile模块. 为什么要使用Mobile呢? ...

  4. Vue电商SKU组合算法问题

    前段时间,公司要做“添加商品”业务模块,这也算是电商业务里面的一个难点了. 令我印象最深的不是什么“组合商品”.“关联商品”.“关联单品”,而是商品SKU的组合问题. 这个问题特别有意思,当时虽然大体 ...

  5. 【学习笔记】线段树—扫描线补充 (IC_QQQ)

    [学习笔记]线段树-扫描线补充 (IC_QQQ) (感谢 \(IC\)_\(QQQ\) 大佬授以本内容的著作权.此人超然于世外,仅有 \(Luogu\) 账号 尚可膜拜) [学习笔记]线段树详解(全) ...

  6. 关于二分查找 使用 lower_bound

    在寻找单调递增最长自序列 , 的时候能不能确认出来哪个是单调递增最长自序列  ?  我的想法是 if(location>=num) dp[location]=b; 这样的 , 基于http:// ...

  7. 如何调用com组件中包含IntPtr类型参数的函数

    背景 公司的支付平台最近对接了西安移动的支付接口,接口中签名的方法是对方提供了一个com组件,组件中包含了一个签名的方法和一个验签的方法,注册了签名之后,在vs中进行了引用,引用之后,查看组件的定义如 ...

  8. 【反射】Java反射机制

    Class 1.Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性    2.对象照镜子后(反射)可以 ...

  9. FFmpeg编译Android版本

    FFmpeg是很好用的一个音视频库,功能强大,但是用起来并不是很方便.之前一直不想用FFmpeg,因为感觉编译太麻烦,但是到了不得不用的时候了,没办法,参考了网上大神的方法,在这里自己也记录一下方便以 ...

  10. 一篇文章告诉你如何使用EF CodeFirst做增删改查

    一.修改数据 其实修改涉及的内容挺多的,是相对于其他操作来说比较繁琐.也是本文的重头戏. 虽然都是基础内容,但是也是值得细细品味的. 1.最简单直接的修改数据就是从数据库里检索出数据修改相应的字段即可 ...