一、what is a shuffle?

  1.1 shuffle简介

  一个stage执行完后,下一个stage开始执行的每个task会从上一个stage执行的task所在的节点,通过网络传输获取task需要处理的所有key,然后每个task对相同的key进行算子操作,这个过程就是shuffle过程。

  我们常说的shuffle过程之所以慢是因为有大量的磁盘IO以及网络传输操作。spark中负责shuffle的组件主要是ShuffleManager,在spark1.1之前采用的都是HashShuffleManager,在1.1之后开始引入效果更优SortShuffleManager,并在1.2开始默认使用SortShuffleManager。

  1.2 HashShuffleManager

  我们来看下最初的ShuffleManager:HashShuffleManager中shuffle的读写过程

  

  从上图我们可以看出,Executor中每个core对应的task在shuffle写的时候都会产生和下一个stage包含task数目一样的磁盘文件,也就是说下一个stage包含多少个task(即Reducer),当前stage的task就会产生多少个磁盘文件。那么100个单核的Executor,当前stage有200个task,每个Executor负责执行2个task,下一个stage有100个task,那么一次shuffle write需要产生200*100=20000个磁盘文件。每个buffer(即图中的bucket)的大小默认为32KB(Spark1.1中默认是100KB,可以通过spark.shuffle.file.buffer.kb来设置);在shuffle read阶段每个task从上一个stage中的每一个task中通过网络传输拉取相同key的数据进行聚合等shuffle操作。所以产生的磁盘文件越多,shuffle read的IO操作就越频繁,且大量的buffer将对Executor的存储空间产生巨大的压力。

  Spark团队对针对“磁盘文件多”这一弊端进行了优化,优化后的HashShuffleManager的shuffle的读写过程:

  

  从上图我们可以看出,下一个stage的每个task的入度变成了优化前的一半,主要是因为每个core都产生了和下一个stage的task相同数目的磁盘文件,同一core中的不同task复用一批磁盘文件,减少磁盘文件数据,提升shuffle write性能。那么与上面相同环境下,优化后需要产生的磁盘文件数量为Executor数*Executor的core数*下一个stage的task数=100*1*100=10000。可以通过将spark.shuffle.consolidateFiles设置为true来开启consolidate机制,即优化后的HashShuffleManager。

  1.3 sortShuffleManager

  Spark 1.2 后开始默认使用sortShuffleManager

  

  SortShuffleManager主要改进点是在内存溢写到磁盘文件之前,会根据Partition id以及key对内存数据进行sort排序,然后再分批写入磁盘文件,分批的batch数量大小为1w条,最后将产生的多个磁盘文件merge成一个磁盘文件,并产生一个索引文件,用以标识下游stage中的各个task的数据在文件中的start offset 和 end offset,直观来看,一个task仅产生一个磁盘文件和一个索引文件。产生的磁盘文件少了,但增加了排序的性能开销,如果这部分在你的业务场景下开销大,那么可以选择SortShuffleManager的bypass机制。

  在ShuffleManager一路优化的过程中,一个重要优化思想其实就是在减少shuffle过程中产生磁盘文件数量,一个直观的逻辑:磁盘文件少,上下游stage需要进行的磁盘IO操作就相对少了。而磁盘文件过多会带来以下问题:

  如果磁盘文件多,进行shuffle操作时需要同时打开的文件数多,大量的文件句柄和写操作分配的临时内存将对内存和GC带来压力,特别是在YARN的模式下,往往Executor分配的内存不足以支持这么大的内存压力;

  如果磁盘文件多,那么其所带来的随机读写需要多次磁盘寻道和旋转延迟,比顺序读写的时间多许多倍。

  可以通过Spark.shuffle.manager参数来设置使用哪种shuffle manager。

  以上我们介绍了what is a shuffle,shuffle write 与 shuffle read的过程,以及为什么shuffle对spark任务性能消耗大,在整体上了解shuffle之后,我们来了解下如何handle shuffle。

  二、判断定位

  spark web ui 上task的执行时间或分配的数据量,如果一般task执行时间只有几秒,而某些task执行时间是几分钟甚至更久,那这部分task对于的stage就出现了数据倾斜,根据之前的stage的划分方式即可定位哪段代码中的算子导致了数据倾斜。

  常见的触发shuffle操作的算子:distinct、groupByKey、reduceByKey、aggregateByKey、join、cogroup、repartition等

  三、深究key分布

  如果是数据倾斜的数据来源于hive表,那么我们可以分析下spark sql中key的数据分布情况

  如果数据来源于中间的RDD,那么可以使用RDD.countByKey()来统计不同key出现的次数

  如果数据量大,可以使用采样来分析,比如:

  val sampledRDD = shuffleRDD.sample(false, 0.1)

  val sampledKeyCounts = sampledRDD.countByKey()

  sampledKeyCounts.foreach(println(_))

  四、How to fix it?

  数据来源于hive表,将导致数据倾斜的shuffle算子前置到**hive ETL(提取、转换和加载)**中,之后的spark任务可反复基于hive ETL后的中间表,保证了spark任务的性能。适用于多次数据计算,且对spark性能要求高的场景。

  不是所有的数据都有用,如果filter少数几个数据量大的key不影响数据结果,那在数据预处理的时候可以进行过滤,或者需要动态判定key是否有用,可以在数据计算前对RDD进行sample采样,过滤数据量大的key,这样不仅可以避免数据倾斜,也可以避免相同的代码在某天突然OOM的情况,有可能这一天有某个平时表现正常的key暴增导致OOM。

  shuffle算子并行操作,我们知道在shuffle过程中,分布在不同task的相同key的数据会通过网络传输到同一个task进行shuffle计算,这时候一个task可能会处理多种key的数据,比如k1,k2,k3可能都被拉取到某一个task上进行reduce操作,如果k1,k2,k3的数量比较大,我们可以通过提高reduce的并行度来使得k1,k2,k3的数据分别拉取到t1,t2,t3三个task上计算,怎么做呢?如果是RDD的shuffle操作,给shuffle算子传入一个参数即可,比如reduceByKey(600),如果是Spark SQL的shuffle操作,配置一个shuffle参数:spark.sql.shuffle.partitions,该参数表示shuffle read task的并行度,默认200,可根据业务场景进行修改。

  key 散列设计再聚合,spark的shuffle操作导致的数据倾斜问题在一定意义上可以类比HBase的热点问题,因此HBase的rowkey的散列设计思想可以套用在聚合类的shuffle操作导致的数据倾斜的场景,怎么做呢?先对key进行hash散列,可以使用随机数,也可以针对key的具体内容进行hash,目的是将原本数据量大的key先hash成k个的key,那么原本必须拉取到一个task上进行shuffle计算的数据可以拉取到k个不同的task上计算,在一定程度上可以缓解单个task处理过多数据导致的数据倾斜,然后再对局部聚合后的key去除hash再聚合。这种key散列设计思想在解决join的shuffle操作广泛使用。

  ”map join replace “reduce join”,如果join操作是大小表的join,可以考虑将小表广播,首先collect到driver的内存中,为其创建一个broadcase变量,这时候Driver和每个Executor都会保存一份小表的全量数据,再在map操作中自定义join的逻辑,在这个join逻辑里,使用已在内存中的全量的小表数据与大表的每一条数据进行key对比连接,用map join来代替普通的reduce join,可以避免数据倾斜。由于需要在内存中存放全量小表,所以小表数据量在一两G是可取的。

Spark 数据倾斜调优的更多相关文章

  1. 最详细10招Spark数据倾斜调优

    最详细10招Spark数据倾斜调优 数据量大并不可怕,可怕的是数据倾斜 . 数据倾斜发生的现象 绝大多数 task 执行得都非常快,但个别 task 执行极慢. 数据倾斜发生的原理 在进行 shuff ...

  2. Spark学习之路 (九)SparkCore的调优之数据倾斜调优

    摘抄自:https://tech.meituan.com/spark-tuning-pro.html 数据倾斜调优 调优概述 有的时候,我们可能会遇到大数据计算中一个最棘手的问题——数据倾斜,此时Sp ...

  3. Spark(十)Spark之数据倾斜调优

    一 调优概述 有的时候,我们可能会遇到大数据计算中一个最棘手的问题——数据倾斜,此时Spark作业的性能会比期望差很多.数据倾斜调优,就是使用各种技术方案解决不同类型的数据倾斜问题,以保证Spark作 ...

  4. Spark性能优化:数据倾斜调优

    前言 继<Spark性能优化:开发调优篇>和<Spark性能优化:资源调优篇>讲解了每个Spark开发人员都必须熟知的开发调优与资源调优之后,本文作为<Spark性能优化 ...

  5. Spark学习之路 (九)SparkCore的调优之数据倾斜调优[转]

    调优概述 有的时候,我们可能会遇到大数据计算中一个最棘手的问题--数据倾斜,此时Spark作业的性能会比期望差很多.数据倾斜调优,就是使用各种技术方案解决不同类型的数据倾斜问题,以保证Spark作业的 ...

  6. Spark性能优化--数据倾斜调优与shuffle调优

    一.数据倾斜发生的原理 原理:在进行shuffle的时候,必须将各个节点上相同的key拉取到某个节点上的一个task来进行处理,比如按照key进行聚合或join等操作.此时如果某个key对应的数据量特 ...

  7. Spark面试题(五)——数据倾斜调优

    1.数据倾斜 数据倾斜指的是,并行处理的数据集中,某一部分(如Spark或Kafka的一个Partition)的数据显著多于其它部分,从而使得该部分的处理速度成为整个数据集处理的瓶颈. 数据倾斜俩大直 ...

  8. 【转】数据倾斜是多么痛?spark作业/面试/调优必备秘籍

    原博文出自于: http://sanwen.net/a/gqkotbo.html 感谢! 来源:数盟 调优概述 有的时候,我们可能会遇到大数据计算中一个最棘手的问题——数据倾斜,此时Spark作业的性 ...

  9. 【Spark篇】---Spark调优之代码调优,数据本地化调优,内存调优,SparkShuffle调优,Executor的堆外内存调优

    一.前述 Spark中调优大致分为以下几种 ,代码调优,数据本地化,内存调优,SparkShuffle调优,调节Executor的堆外内存. 二.具体    1.代码调优 1.避免创建重复的RDD,尽 ...

随机推荐

  1. java的this表示当前类还是当前实例?

    转自:http://www.runoob.com/java/java-basic-syntax.html this 表示调用当前实例或者调用另一个构造函数

  2. ST-LINK使用注意

    利用ST-LINK下载程序注意事项: 1.接线 按照上面图对着自己的开发板连接相应的引脚就可以了. 2.keil5配置 线连接完之后,要对自己的工程进行相关的 配置才能正确进行下载. 首先选择ST-L ...

  3. 三维凸包求其表面积(POJ3528)

    Ultimate Weapon Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 2074   Accepted: 989 D ...

  4. js获取元素的外链样式

    一般给元素设置行内样式,如<div id="div1" style="width:500px;"></div>.如要获取它的样式,即可d ...

  5. T-SQL数据库备份

    /*1.--得到数据库的文件目录 @dbname 指定要取得目录的数据库名 如果指定的数据不存在,返回安装SQL时设置的默认数据目录 如果指定NULL,则返回默认的SQL备份目录名 */ /*--调用 ...

  6. talib 中文文档(十二):Pattern Recognition Functions K线模式识别,形态识别

    Pattern Recognition Functions K线模式识别,形态识别 CDL2CROWS - Two Crows 函数名:CDL2CROWS 名称:Two Crows 两只乌鸦 简介:三 ...

  7. python 面向对象 公有属性 用在哪里

    公有属性也可以叫做静态字段 如果每个对象都有一个共同的值 , 应该把它设置为公有属性 公有属性使用场景,每个对象中保存相同的东西时,可以使用公有属性 类找公有属性 过程

  8. PAT 1137 Final Grading[一般][排序]

    1137 Final Grading(25 分) For a student taking the online course "Data Structures" on China ...

  9. 2.2 The Object Model -- Reopening Classes and Instances

    1. 你不需要一开始定义一个类的全部内容,你可以通过使用reopen方法重新打开一个类并定义新的属性. Person.reopen({ isPerson: true }); Person.create ...

  10. Linux系统——搭建FTP方式的本地定制化Yum仓库

    (1)搭建公网源yum仓库 安装wget aliyun源 # wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epe ...