大数据Spark Shuffle | 青训营笔记

123 阅读3分钟

这是我参与「第四届青训营 」笔记创作活动的第1天

今天复习了Spark Shuffle课程,二刷受益匪浅。

1. Shuffle概述

(1)MapReduce编程模型包含mapshufflereduce三个阶段

Map阶段:是在单机上进行的针对一小块数据的计算过程。

Shuffle阶段:在map的基础上进行数据移动,为后续的reduce做准备。

Reduce阶段:对移动后的数据进行处理。

(2)shuffle为什么影响性能?

  • 存在M*R次数据移动,网络连接消耗太大
  • 可能存在大量的record排序
  • java对象在网络中传输还存在大量序列化/反序列化
  • 数据压缩

2. Spark Shuffle

(1)宽依赖/窄依赖

窄依赖:父RDD的每个分片至多被子RDD中的一个分片所以来

宽依赖:父RDD中的分片可能被子RDD中的多个分片所以来

当出现宽依赖(ShuffleDependency)Spark就会把运算拆分成两个Stage,即map stagereduce stage产生 Shuffle

(2)Shuffle Dependency-Partitioner

两个接口:numberPartitions 和 getPartition

经典实现:HashPartitioner(先对K取Hashcode,在对分区数取余数)

(3)Shuffle Dependency-Aggregator

createCombiner:只有一个value的时候初始化的方法

mergeValue:合并一个value到Aggregator

mergeCombiners:合并两个Aggregator

3. HashShuffle

Spark1.2以前,默认使用HashShuffle

每个partition有一个Buffer,直接把partition写到不同的文件中。

最终产生M*R个小文件。

(1) 普通HashShuffle

MapTask会根据ReduceTask的个数将数据分成多个partition(hash % numReduce),同时每个partition会单独溢写到一个独立文件中,最终产生M*R个小文件。

image.png

缺点:

  • Shuffle阶段在磁盘上产生了过多的小文件,reduce端在拉取数据时会消耗大量IO资源和网络资源。
  • 频繁IO,导致读写磁盘时创建对象过多,使堆内存不足,导致OOM。

(2) 优化HashShuffle

开启合并机制(spark.shuffle.consolidateFiles),把每个partition数据映射成为一个文件片段。根据申请到的CPU Core进行写文件,最终会产生C*R个文件。

image.png

缺点:

  • 如果reduceTask的个数过多仍然会产生过多小文件,造成OOM

4. SortShuffle

(1) SortShuffle

同一个MapTask下的partitions共享buffer,溢写之前进行排序,形成溢写临时文件,最终将所有一些临时文件进行合并生成最终数据文件和索引文件。

image.png

(2) bypassMergeShuffle

类似于HashShuffle,但最终还合并所有溢写临时文件生成最终数据文件和索引文件

(3) UnsafeShuffle

使用堆外空间进行溢写,因此成为unsafe;因为在堆外不存在Java对象开销,别不对record进行排序,效率更优。

5. Shuffle优化

Shuffle存在的问题:

  • 数据本地存储没有备份
  • IO并发,大量RPC请求
  • IO吞吐,随机读,写放大
  • GC频繁,影响NodeManager

Shuffle优化:

  • 1.如果某个RDD数据量很小(1G~2G),那就接使用broadcast替代join
  • 2.使用map-side combine,对数据进行预聚合。
  • 3.Shuffle参数的优化

Shuffle数据倾斜解决方案:

  • 提高并行度,分摊拉取数据量
  • Spark 3.0增加AQE功能,自动发现打散倾斜数据。
  • Spark运行参数的调参,利用mapside combine

6. Push Shuffle

TODO: