Spark学习笔记_3_SparkShuffle

Spark中的Shuffle过程涉及数据重分布,产生大量磁盘I/O和网络开销。Map任务根据Reduce任务数量创建桶,数据通过哈希分区写入。新版本中,多个桶写入一个文件以减少文件数量。Reduce端使用Aggregator而非归并排序,节省计算资源。然而,增加任务数量虽能减小分区大小,但也增加内存消耗,可能导致内存溢出。为减少内存使用,Shuffle过程可能需将部分操作移至磁盘。
摘要由CSDN通过智能技术生成

一、Spark中的Shuffle

Spark 中的一些操作会触发 Shuffle 过程,这个过程涉及到数据的重新分发,因此,会产生大量的磁盘I/O和网络开销,Shuffle的过程(即把Map输出的中间结果分发到Reduce任务所在的机器),会产生大量的网络数据分发,带来高昂的网络传输开销。
在这里插入图片描述
首先,在Map端的Shuffle写入(Shuffle Write)方面。每一个Map任务会根据Reduce任务的数量创建出相应的桶(Bucket),因此,桶的数量是m×r,其中,m是Map任务的个数,r是Reduce任务的个数。Map任务产生的结果会根据设置的分区(partition)算法填充到每个桶中去。分区算法可以自定义,也可以采用系统默认的算法;默认的算法是根据每个键值对(key,value)的key,把键值对哈希到不同的桶中去。当Reduce任务启动时,它会根据自己任务的id和所依赖的Map任务的id,从远端或是本地取得相应的桶,作为Reduce任务的输入进行处理。

此处桶是一个抽象概念,在实现中每个桶可以对应一个文件,也可以对应文件的一部分。但是,从性能角度而言,每个桶对应一个文件的实现方式,会导致Shuffle过程生成过多的文件。例如,如果有1000个Map任务和1000个Reduce任务,就会生成100万个文件,这样会给文件系统带来沉重的负担。

因此,在新的Spark版本中,采用了多个桶写入一个文件的方式(见下图)。每个Map任务不会为每个Reduce任务单独生成一个文件,而是把每个Map任务所有的输出数据只写到一个文件中。因为每个 Map 任务中的数据会被分区,所以使用了索引(Index)文件来存储具体 Map 任务输出数据在同一个文件中是如何被分区的信息。Shuffle过程中每个Map任务会产生两个文件,即数据文件索引文件,其中,数据文件是存储当前Map任务的输出结果,而索引文件中则存储了数据文件中的数据的分区信息。下一个阶段的Reduce任务就是根据索引文件来获取属于自己处理的那个分区的数据。
在这里插入图片描述
其次,在Reduce端的Shuffle读取(Shuffle Fetch)方面,Spark并不在 Reduce 端做归并和排序,而是采用了称为 Aggregator 的机制。

在Hadoop MapReduce的Shuffle过程中,在Reduce端,Reduce任务会到各个Map任务那里把数据自己要处理的数据都拉到本地,并对拉过来的数据进行归并(Merge)和排序(Sort),使得相同key的不同value按序归并到一起,供Reduce任务使用。

Spark假定在大多数应用场景中,Shuffle数据的排序操作不是必须的,比如在进行词频统计时,如果强制地进行排序,只会使性能变差,因此,Spark并不在 Reduce 端做归并和排序,而是采用了称为 Aggregator 的机制。

Aggregator 本质上是一个HashMap,里面的每个元素是<K,V>形式。以词频统计为例,它会将从 Map 端拉取到的每一个(key,value),更新或是插入到HashMap中,若在HashMap中没有查找到这个key,则把这个(key,value)插入其中,若查找到这个key,则把value的值累加到V上去。这样就不需要预先把所有的(key,value)进行归并和排序,而是来一个处理一个,避免了外部排序这一步骤。

需要注意的是,Reduce任务所拥有的内存,必须足以存放属于自己处理的所有key和value值,否则就会产生内存溢出问题。

二、SparkShuffle遇到的问题

上边已经说明了SparkShuffle的大致内容,值得注意的是Spark总是基于内存计算,因此,Spark文档中建议用户涉及到这类操作的时候尽量增加分区的数量,也就是增加Map和Reduce任务的数量。

增加分区数量就是增加Map和Reduce任务的数量,这样做的好处是缓解在Shuffle的过程中,让单个Reduce的内存能够容纳整个分区的数据。

增加Map和Reduce任务的数量虽然可以减小分区的大小,使得内存可以容纳这个分区。但是,在Shuffle 写入环节,桶的数量是由Map和Reduce任务的数量决定的,任务越多,桶的数量就越多,就需要更多的缓冲区(Buffer),带来更多的内存消耗。

因此,在内存使用方面,我们会陷入一个两难的境地,一方面,为了减少内存的使用,需要采取增加Map和Reduce任务数量的策略,另一方面,Map和Reduce任务数量的增多,又会带来内存开销更大的问题。最终,为了减少内存的使用,只能将Aggregator的操作从内存移到磁盘上进行。也就是说,尽管Spark经常被称为“基于内存的分布式计算框架”,但是,Spark的Shuffle过程依然需要把数据写入磁盘

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aimyon_36

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值