热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

149、Spark核心编程进阶之Shuffle相关

shuffle操作原理 是spark中一些特殊的算子操作会触发的一种操作 shuffle操作,会导致大量的数据在不同的机器和节点之间进行传输,因此也是spark中最复杂、最

shuffle操作原理

是spark中一些特殊的算子操作会触发的一种操作
shuffle操作,会导致大量的数据在不同的机器和节点之间进行传输,因此也是spark中最复杂、最消耗性能的一种操作

我们可以通过reduceByKey操作作为一个例子,来理解shuffle操作
先看图

 

13274599-2daa4604817e7ab3.png

shuffle操作原理.png

reduceByKey算子会将上一个RDD中的每个key对应的所有value都聚合成一个value,然后生成一个新的RDD
新的RDD的元素类型就是对的格式,每个key对应一个聚合起来的value
这里最大的问题就在于,对于上一个RDD来说,并不是一个key对应的所有value都是在一个partition中的,也更不太可能说key的所有value都在一台机器上
所以对于这种情况来说,就必须在整个集群中,将各个节点上,同一个key对应的values,统一传输到一个节点上来聚合处理
这个过程中就会发生大量的网络数据的传输

在进行一个key对应的values的聚合时
首先,上一个stage的每个map task就必须保证将自己处理的当前分区中的数据,相同的key写入一个分区文件中,可能会写多个不同的分区文件
接着下一个stage的reduce task就必须从上一个stage所有task所在的机器上,将各个task写入的多个分区文件中,找到属于自己的那个分区文件
接着将属于自己的分区数据,拉取过来,这样就可以保证每个key对应的所有values都汇聚到一个节点上去处理和聚合
这个过程就称之为shuffle

shuffle是分为shuffle write和shuffle read两个部分的,是在两个不同的stage中进行的

shuffle操作过程中进行数据排序

默认情况下,shuffle操作是不会对每个分区中的数据进行排序的

如果想要对每个分区中的数据进行排序,那么可以使用以下三种方法:

  1. 使用mapPartitions算子处理每个partition,对每个partition中的数据进行排序
  2. 使用repartitionAndSortWithinPartitions,对RDD进行重分区,在重分区的过程中同时就进行分区内数据的排序
  3. 使用sortByKey对数据进行全局排序

上述三种方法中,相对来说,mapPartitions的代价比较小,因为不需要进行额外的shuffle操作
repartitionAndSortWithinPartitions和sortByKey可能会进行额外的shuffle操作的,因此性能并不是很高

val rdd2 = rdd1.reduceByKey(_ + _)
rdd2.mapPartitions(tuples.sort)
rdd2.repartitionAndSortWithinPartitions(),重分区,重分区的过程中,就进行分区内的key的排序,重分区的原理和repartition一样
rdd2.sortByKey,直接对rdd按照key进行全局性的排序

spark中会导致shuffle操作

spark中会导致shuffle操作的有以下几种算子

  1. repartition类的操作:比如repartition、repartitionAndSortWithinPartitions、coalesce等
  2. byKey类的操作:比如reduceByKey、groupByKey、sortByKey等
  3. join类的操作:比如join、cogroup等

重分区: 一般会shuffle,因为需要在整个集群中,对之前所有的分区的数据进行随机,均匀的打乱,然后把数据放入下游新的指定数量的分区内
byKey类的操作:因为你要对一个key,进行聚合操作,那么肯定要保证集群中,所有节点上的,相同的key,一定是到同一个节点上进行处理
join类的操作:两个rdd进行join,就必须将相同join key的数据,shuffle到同一个节点上,然后进行相同key的两个rdd数据的笛卡尔乘积

所以对于上述的操作
首先第一原则,就是,能不用shuffle操作,就尽量不用shuffle操作,尽量使用不shuffle的操作
第二原则,就是,如果使用了shuffle操作,那么肯定要进行shuffle的调优,甚至是解决碰到的数据倾斜的问题

shuffle操作对性能消耗的原理

shuffle操作是spark中唯一最最消耗性能的地方
因此也就成了最需要进行性能调优的地方,最需要解决线上报错的地方,也是唯一可能出现数据倾斜的地方
因为shuffle过程中,会产生大量的磁盘IO、数据序列化和反序列化、网络IO

为了实施shuffle操作
spark中才有了stage的概念,在发生shuffle操作的算子中,进行stage的拆分
shuffle操作的前半部分,是上一个stage来进行,也称之为map task,shuffle操作的后半部分,是下一个stage来进行,也称之为reduce task
其中map task负责数据的组织,也就是将同一个key对应的value都写入同一个下游task对应的分区文件中
其中reduce task负责数据的聚合,也就是将上一个stage的task所在节点上,将属于自己的各个分区文件,都拉取过来聚合
这种模型,是参考和模拟了MapReduce的shuffle过程来的

map task会将数据先保存在内存中,如果内存不够时,就溢写到磁盘文件中去
reduce task会读取各个节点上属于自己的分区磁盘文件,到自己节点的内存中,并进行聚合

shuffle操作会消耗大量的内存,因为无论是网络传输数据之前,还是之后,都会使用大量的内存中数据结构来实施聚合操作
比如reduceByKey和aggregateByKey操作,会在map side使用内存中的数据结构进行预先聚合
其他的byKey类的操作,都是在reduce side,使用内存数据结构进行聚合
在聚合过程中,如果内存不够,只能溢写到磁盘文件中去,此时就会发生大量的磁盘IO,降低性能

此外,shuffle过程中,还会产生大量的中间文件,也就是map side写入的大量分区文件
比如Spark 1.3版本,这些中间文件会一致保留着,直到RDD不再被使用,而且被垃圾回收掉了,才会去清理中间文件
这主要是为了,如果要重新计算shuffle后的RDD,那么map side不需要重新做一次磁盘写操作
但是这种情况下,如果我们的应用程序中,一直保持着对RDD的引用,导致很长时间以后才会进行RDD垃圾回收操作
保存中间文件的目录,由spark.local.dir属性指定

内存的消耗、磁盘IO、网络数据传输(IO)

shuffle操作所有相关参数详解以及性能调优

我们可以通过对一系列的参数进行调优,来优化shuffle的性能
spark 1.5.2版本

属性名称默认值属性说明
spark.reducer.maxSizeInFlight48mreduce task的buffer缓冲,代表了每个reduce task每次能够拉取的map side数据最大大小,如果内存充足,可以考虑加大大小,从而减少网络传输次数,提升性能
spark.shuffle.blockTransferServicenettyshuffle过程中,传输数据的方式,两种选项,netty或nio,spark 1.2开始,默认就是netty,比较简单而且性能较高,spark 1.5开始nio就是过期的了,而且spark 1.6中会去除掉
spark.shuffle.compresstrue是否对map side输出的文件进行压缩,默认是启用压缩的,压缩器是由spark.io.compression.codec属性指定的,默认是snappy压缩器,该压缩器强调的是压缩速度,而不是压缩率
spark.shuffle.consolidateFilesfalse默认为false,如果设置为true,那么就会合并map side输出文件,对于reduce task数量特别的情况下,可以极大减少磁盘IO开销,提升性能
spark.shuffle.file.buffer32kmap side task的内存buffer大小,写数据到磁盘文件之前,会先保存在缓冲中,如果内存充足,可以适当加大大小,从而减少map side磁盘IO次数,提升性能
spark.shuffle.io.maxRetries3网络传输数据过程中,如果出现了网络IO异常,重试拉取数据的次数,默认是3次,对于耗时的shuffle操作,建议加大次数,以避免full gc或者网络不通常导致的数据拉取失败,进而导致task lost,增加shuffle操作的稳定性
spark.shuffle.io.retryWait5s每次重试拉取数据的等待间隔,默认是5s,建议加大时长,理由同上,保证shuffle操作的稳定性
spark.shuffle.io.numConnectionsPerPeer1机器之间的可以重用的网络连接,主要用于在大型集群中减小网络连接的建立开销,如果一个集群的机器并不多,可以考虑增加这个值
spark.shuffle.io.preferDirectBufstrue启用堆外内存,可以避免shuffle过程的频繁gc,如果堆外内存非常紧张,则可以考虑关闭这个选项
spark.shuffle.managersortShuffleManager,Spark 1.5以后,有三种可选的,hash、sort和tungsten-sort,sort-based ShuffleManager会更高效实用内存,并且避免产生大量的map side磁盘文件,从Spark 1.2开始就是默认的选项,tungsten-sort与sort类似,但是内存性能更高
spark.shuffle.memoryFraction0.2如果spark.shuffle.spill属性为true,那么该选项生效,代表了executor内存中,用于进行shuffle reduce side聚合的内存比例,默认是20%,如果内存充足,建议调高这个比例,给reduce聚合更多内存,避免内存不足频繁读写磁盘
spark.shuffle.service.enabledfalse启用外部shuffle服务,这个服务会安全地保存shuffle过程中,executor写的磁盘文件,因此executor即使挂掉也不要紧,必须配合spark.dynamicAllocation.enabled属性设置为true,才能生效,而且外部shuffle服务必须进行安装和启动,才能启用这个属性
spark.shuffle.service.port7337外部shuffle服务的端口号,具体解释同上
spark.shuffle.sort.bypassMergeThreshold200对于sort-based ShuffleManager,如果没有进行map side聚合,而且reduce task数量少于这个值,那么就不会进行排序,如果你使用sort ShuffleManager,而且不需要排序,那么可以考虑将这个值加大,直到比你指定的所有task数量都打,以避免进行额外的sort,从而提升性能
spark.shuffle.spilltrue当reduce side的聚合内存使用量超过了spark.shuffle.memoryFraction指定的比例时,就进行磁盘的溢写操作
spark.shuffle.spill.compresstrue同上,进行磁盘溢写时,是否进行文件压缩,使用spark.io.compression.codec属性指定的压缩器,默认是snappy,速度优先

推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • Windows7企业版怎样存储安全新功能详解
    本文介绍了电脑公司发布的GHOST WIN7 SP1 X64 通用特别版 V2019.12,软件大小为5.71 GB,支持简体中文,属于国产软件,免费使用。文章还提到了用户评分和软件分类为Win7系统,运行环境为Windows。同时,文章还介绍了平台检测结果,无插件,通过了360、腾讯、金山和瑞星的检测。此外,文章还提到了本地下载文件大小为5.71 GB,需要先下载高速下载器才能进行高速下载。最后,文章详细解释了Windows7企业版的存储安全新功能。 ... [详细]
  • 本文讨论了如何使用GStreamer来删除H264格式视频文件中的中间部分,而不需要进行重编码。作者提出了使用gst_element_seek(...)函数来实现这个目标的思路,并提到遇到了一个解决不了的BUG。文章还列举了8个解决方案,希望能够得到更好的思路。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 本文介绍了使用数据库管理员用户执行onstat -l命令来监控GBase8s数据库的物理日志和逻辑日志的使用情况,并强调了对已使用的逻辑日志是否及时备份的重要性。同时提供了监控方法和注意事项。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
author-avatar
mobiledu2502886333
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有