Spark的Shuffle
0. Shuffle概述
要理解什么是Shuffle,首先介绍大数据与分布式。我们知道大数据的存储是分布式存储,大数据的计算框架是分布式的计算框架。分布式必然存在数据的交互传输,简言之Shuffle就是分布式中数据交互传输的过程。
如下图所示,Stage 0的输出数据需要经过shuffle Writer写出到Block中,Stage 1的输入数据需要从Block中读入,这一中间结果的写出读入过程就是一次Shuffle。
图1
那么问题来了,为什么Stage 0的数据不能直接交给Stage 1处理,非要经过Shuffle过程呢?
这里我们从Stage的划分开始说起,Stage划分的依据是RDD的宽窄依赖,宽窄依赖的划分依据参考此文:https://www.cnblogs.com/beichenroot/p/11414173.html
RDD之所以会存在宽窄依赖,与Spark天生的属性有关,Spark是分布式计算引擎,RDD是弹性分布式数据集,是Spark中处理数据的逻辑单位。RDD的数据存储方式如下图所示:图中RDD数据分别存储在三个节点不同的Executor的分区(Partition)中,分区可以理解为Block的不同表述,一个分区对应一个Block,这三个不同节点上的分区一起构成一个RDD。
回到正题,由于RDD的数据存在不同的节点上,分布式计算在不同节点上并行进行,如果是窄依赖,即分区间的数据不需要交互,则数据在本分区内操作;如果是宽依赖,数据需要往其他分区传送,则必然产生数据的读写,则存在Shuffle。
1. Shuffle的重要性
由图1Shuffle的过程可知,Shuffle过程包含三部分:
1. Shuffle的Wiiter
2. 网络传输
3. Shuffle的Read
这三部分操作包含内存操作、磁盘I/O、网络I/O以及JVM管理,影响了Spark应用程序的绝大部分效率。对于好的程序代码,大部分的性能(95%)都消耗在Shuffle阶段的本地写磁盘文件、网络传输数据及抓取数据中。所以Spark针对Shuffle过程做了大量优化。
2. Spark Shuffle的发展过程
Spark Shuffle早期采用的是HashShuffle,HashShuffle最大的问题是产生的文件数量(Mapper分片数量 * Reducer的分片数量)太多,导致大量的IO内存消耗以及沉重的GC负担;
Spark采用SortedBasedShuffle根据Map Task的数量来生成文件,如下图所示,每个Map任务会生成两个文件,一个是数据文件分片写入,一个是偏移量文件,记录了每个分片的相关信息。Reduce任务读取数据时首先从偏移量文件中获取数据的位置,再到数据文件中读取数据。SortedBasedShuffle将Shuffle中的文件数量降低到了2 * Map任务个数,带来的优化如下:
1. Mapper端占用内存变少
2. 增加了Spark处理大规模数据的能力(可并行的任务数增加)
3. Reducer端抓取数据的次数变少
4. 网络通道的句柄变少
5. 减少了数据本身对内存的消耗
Spark Shuffle详细内容可参考此文:https://www.cnblogs.com/itboys/p/9226479.html
3. Shuffle与Storage模块间的交互
Spark中存储模块被抽象成Storage,Storage代表着Spark中的数据存储系统,负责管理数据块(Block),Block是存取数据的最小单元,等价于RDD中的Partition。
Storage抽象模块分为两个层次:
1. 通信层:通信层是典型的主从结构,Master和Slave之间传输控制和状态信息。通信层主要由BlockManager、BlockManagerMaster、BlockManagerMasterEndPoint、BlockManagerSlaverEndPoint等类实现。
2. 存储层:负责把数据存储到内存、磁盘或者堆外内存中,有时还需要为数据在远程节点上生成副本。Spark存储层的实现类有DiskStore和MemoryStore。
Shuffle过程中进行的数据读写实质是通过操作BlockManager接口来实现的。
3.1 BlockManager架构
1. Application启动时会在SparkEnv中注册BlockManagerMaster以及MapOutputTracker
a. BlockManagerMaster:对整个集群的Block数据进行管理
b. MapOutputTracker:跟踪所有的Mapper输出
2. 构建BlockManagerMaster时会创建BlockManagerMasterEndPoint,BlockManagerMasterEndPoint本身是一个消息体,负责通过远程通信的方式管理所有节点的BlockManager。
3. 没启动一个ExecutorBackend,都会实例化BlockManager,并通过远程通信的方式注册给BlockManagerMaster;实质上是Executor中的BlockManager在启动时注册给了Driver上的BlockManagerMasterEndPoint。
4. MemoryStore是BlockManager中负责内存数据存储和读写的类。
5. DiskStore是BlockManager中负责磁盘数据存储和读写的类。
6. DiskBlockManager:管理Logical Block与Disk上的Physical Block之间映射关系并负责磁盘文件的创建、读写等。
3.2 Shuffle与BlockManager交互
3.2.1 Shuffle写数据
基于Sort的Shuffle实现的ShuffleHandle包含BypassMergeSortShuffleHandle和BaseShuffleHandle,两种ShuffleHandle对应的数据写入类为BypassMergeSortShuffleWriter和SortShuffleWriter,这里以SortShuffleWriter为例进行梳理。
SortShuffleWriter写数据由下面的write方法实现,首先需要通过ShuffleBlockResolver获取到数据文件。
/** Write a bunch of records to this task's output */
override def write(records: Iterator[Product2[K, V]]): Unit = {
...
// Don't bother including the time to open the merged output file in the shuffle write time,
// because it just opens a single file, so is typically too fast to measure accurately
// (see SPARK-3570).
val output = shuffleBlockResolver.getDataFile(dep.shuffleId, mapId)
...
val tmp = Utils.tempFileWith(output)
try {
val blockId = ShuffleBlockId(dep.shuffleId, mapId, IndexShuffleBlockResolver.NOOP_REDUCE_ID)
val partitionLengths = sorter.writePartitionedFile(blockId, tmp)
shuffleBlockResolver.writeIndexFileAndCommit(dep.shuffleId, mapId, partitionLengths, tmp)
具体调用ShuffleBlockResolver子类IndexShuffleBlockResolver中的getDataFile方法,此处可以看到实际是通过blockManager获取的数据。
def getDataFile(shuffleId: Int, mapId: Int): File = {
blockManager.diskBlockManager.getFile(ShuffleDataBlockId(shuffleId, mapId, NOOP_REDUCE_ID))
}
然后生成ShuffleBlockId,通过ExternalSorter的writePartitionedFile方法最终写出数据。writePartitionedFile实质调用的仍是blockManager中的写方法。所以Shffle写数据底层是由blockManager实现。
def writePartitionedFile(
blockId: BlockId,
outputFile: File): Array[Long] = { // Track location of each range in the output file
val lengths = new Array[Long](numPartitions)
val writer = blockManager.getDiskWriter(blockId, outputFile, serInstance, fileBufferSize,
context.taskMetrics().shuffleWriteMetrics)
3.2. Shuffle读数据
Shuffle读数据是从SortShuffleManager的getReader获取一个数据阅读器,getReader方法中创建了BlockStoreShuffleReader实例。、
BlockStoreShuffleReader的read方法首先实例化ShuffleBlockFetcherIterator。ShuffleBlockFetcherIterator中的成员blockManager管理内存和磁盘数据上的读写。
* ShuffleBlockFetcherIterator中splitLocalRemoteBlocks划分本地和远程的blocks,Utils.randomize(remoteRequests)把远程请求通过随机的方式添加到队列中,fetchUpToMaxBytes发送远程请求获取blocks,fetchLocalBlocks获取本地的blocks。
Spark的Shuffle的更多相关文章
- 【Spark】Spark的Shuffle机制
MapReduce中的Shuffle 在MapReduce框架中,shuffle是连接Map和Reduce之间的桥梁,Map的输出要用到Reduce中必须经过shuffle这个环节,shuffle的性 ...
- 【Spark篇】---Spark中Shuffle文件的寻址
一.前述 Spark中Shuffle文件的寻址是一个文件底层的管理机制,所以还是有必要了解一下的. 二.架构图 三.基本概念: 1) MapOutputTracker MapOutputTracker ...
- 【Spark篇】---Spark中Shuffle机制,SparkShuffle和SortShuffle
一.前述 Spark中Shuffle的机制可以分为HashShuffle,SortShuffle. SparkShuffle概念 reduceByKey会将上一个RDD中的每一个key对应的所有val ...
- Spark 的 Shuffle过程介绍`
Spark的Shuffle过程介绍 Shuffle Writer Spark丰富了任务类型,有些任务之间数据流转不需要通过Shuffle,但是有些任务之间还是需要通过Shuffle来传递数据,比如wi ...
- 研究一下Spark Hash Shuffle 和 SortShuffle 原理机制
研究一下Spark Hash Shuffle 和 SortShuffle 原理机制研究一下Spark Hash Shuffle 和 SortShuffle 原理机制研究一下Spark Hash Shu ...
- 剖析Hadoop和Spark的Shuffle过程差异
一.前言 对于基于MapReduce编程范式的分布式计算来说,本质上而言,就是在计算数据的交.并.差.聚合.排序等过程.而分布式计算分而治之的思想,让每个节点只计算部分数据,也就是只处理一个分片,那么 ...
- [Spark]What's the difference between spark.sql.shuffle.partitions and spark.default.parallelism?
From the answer here, spark.sql.shuffle.partitions configures the number of partitions that are used ...
- spark的shuffle机制
对于大数据计算框架而言,Shuffle阶段的设计优劣是决定性能好坏的关键因素之一.本文将介绍目前Spark的shuffle实现,并将之与MapReduce进行简单对比.本文的介绍顺序是:shuffle ...
- 剖析Hadoop和Spark的Shuffle过程差异(一)
一.前言 对于基于MapReduce编程范式的分布式计算来说,本质上而言,就是在计算数据的交.并.差.聚合.排序等过程.而分布式计算分而治之的思想,让每个节点只计算部分数据,也就是只处理一个分片,那么 ...
- 详细探究Spark的shuffle实现
Background 在MapReduce框架中,shuffle是连接Map和Reduce之间的桥梁,Map的输出要用到Reduce中必须经过shuffle这个环 节,shuffle的性能高低直接影响 ...
随机推荐
- HDU1003 最大连续子序列
Max Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Sub ...
- ECS适合你吗?
实体组件系统处于预览状态.不建议用于生产. 目前有两个很好的理由使用它. 你想试验 这是令人兴奋的新技术,并且大规模性能提升的承诺正在引诱.试试看.给我们您的反馈.我们很乐意在论坛上与您交谈. 您正在 ...
- 最新 前程无忧java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.前程无忧等10家互联网公司的校招Offer,因为某些自身原因最终选择了前程无忧.6.7月主要是做系统复习.项目复盘.Leet ...
- 转换函数conversion function
类转换分为两个角度 转换自身为其他类型 把其他类型转换为自身 Example: 这里我们可以将b转换为class xxx 的类型(方式2),也可以将me转换为double,然后再讲结果转换为doubl ...
- Python时间日期格式化之time与datetime模块
1 引言 在实际开发过程中,我们经常会用到日期或者时间,那么在Python中我们怎么获取时间,以及如何将时间转换为我们需要的格式呢?在之前的开发中,也曾遇到time.datetime等模块下的不同函数 ...
- Java编程思想(四)初始化和清除
4.1用构建器自动初始化 若某个类中有一个构建器,那么在创建对象时,Java会自动调用哪个构建器 在Java中构建器的名字必须与类名相同,这样可以保证这样一个方法惠子初始化期间自动调用: 利用构 ...
- JDBC:数据库连接技术
JDBC :带它再爱你一次 (一) JDBC 入门 (1) 概述 Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问 ...
- [转帖]Linux-Windows 端口转发 netsh 还有 rinetd
Linux-Windows 端口转发 https://www.cnblogs.com/operationhome/p/11284559.html 之前自己学习过 netsh 也曾经用过frp 这次学习 ...
- postgresSQL常用命令
1.createdb 数据库名称 产生数据库2.dropdb 数据库名称 删除数据库 3.CREATE USER 用户名称 创建用户4.drop User 用户名称 删除用户 5.SELEC ...
- System memory 259522560 must be at least 4.718592
[学习笔记] /*没有下面的话, 会报一个错误,java.lang.IllegalArgumentException: System memory 259522560 must be at least ...