一段程序只能完成功能是没有用的,只能能够稳定、高效率地运行才是生成环境所需要的。

本篇记录了Spark各个角度的调优技巧,以备不时之需。

一、配置参数的方式和观察性能的方式

额。。。从最基本的开始讲,可能一些刚接触Spark的人不是很清楚Spark的一些参数变量到底要配置在哪里。

可以通过三种方式配置参数,任选其一皆可。

  1. spark-env.sh文件中配置:最近常使用的配置方式,格式可以参考其中的一些官方保留的配置。
  2. 程序中通过SparkConf配置:通过SparkConf对象set方法设置键值对,比较直观。
  3. 程序中通过System.setProperty配置:和方法二差不多。

值得一提的是一个略显诡异的现象,有些参数在spark-env.sh中配置并不起作用,反而要在程序中设置才有效果。

Spark的参数很多,一些默认的设置可以参考官网推荐的配置参数:/docs/latest/configuration.html

可以通过以下几种方式来观察Spark集群的状态和相关性能问题:

  1. Web UI:即8088端口进入的UI界面。
  2. Driver程序日志:根据程序提交方式的不同到指定的节点上观察Driver程序日志。
  3. logs文件夹下的日志:Spark集群的大部分信息都会记录在这里。
  4. works文件夹下的日志:主要记录Work节点的信息。
  5. Profiler工具:没有使用过。

前景交代完毕,下面进入正题:

二、调度与分区优化

1、小分区合并的问题

由于程序中过度使用filter算子或者使用不当,都会造成大量的小分区出现。

因为每次过滤得到的结果只有原来数据集的一小部分,而这些量很小的数据同样会以一定的分区数并行化分配到各个节点中执行。

带来的问题就是:任务处理的数据量很小,反复地切换任务所消耗的资源反而会带来很大的系统开销。

解决方案:使用重分区函数coalesce进行数据紧缩、减少分区数并设置shuffle=true保证任务是并行计算的

减少分区数,虽然意味着并行度降低,但是相对比之前的大量小任务过度切换的消耗,却是比较值得的。

这里也可以直接使用repartition重分区函数进行操作,因为其底层使用的是coalesce并设置Shuffle=true

2、数据倾斜问题

这是一个生产环境中经常遇到的问题,典型的场景是:大量的数据被分配到小部分节点计算,而其他大部分节点却只计算小部分数据。

问题产生的原因有很多,可能且不全部包括:

  • key的数据分布不均匀
  • 业务数据本身原因
  • 结构化表设计问题
  • 某些SQL语句会造成数据倾斜

可选的解决方案有:

  1. 增大任务数,减少分区数量:这种方法和解决小分区问题类似。
  2. 对特殊的key进行处理,如空值等:直接过滤掉空值的key以免对任务产生干扰。
  3. 使用广播:小数据量直接广播,大数据量先拆分之后再进行广播。

还有一种场景是任务执行速度倾斜问题:集群中其他节点都计算完毕了,但是只有少数几个节点死活运行不完。(其实这和上面的那个场景是差不多的)

解决方案:

  • 设置spark.speculation=true将执行事件过长的节点去掉,重新分配任务
  • spark.speculation.interval用来设置执行间隔

3、并行度调整

官方推荐每个CPU CORE分配2-3个任务。

  • 任务数太多:并行度太高,产生大量的任务启动和切换开销。
  • 任务数太低:并行度过低,无法发挥集群并行计算能力,任务执行慢

Spark会根据文件大小默认配置Map阶段的任务数,所以我们能够自行调整的就是Reduce阶段的分区数了。

  • reduceByKey等操作时通过numPartitions参数进行分区数量配置。
  • 通过spark.default.parallelism进行默认分区数配置。

4、DAG调度执行优化

DAG图是Spark计算的基本依赖,所以建议:

  1. 同一个Stage尽量容纳更多地算子,防止多余的Shuffle。
  2. 复用已经cache的数据。

尽可能地在Transformation算子中完成对数据的计算,因为过多的Action算子会产生很多多余的Shuffle,在划分DAG图时会形成众多Stage。

三、网络传输优化

1、大任务分发问题

Spark采用Akka的Actor模型来进行消息传递,包括数据、jar包和相关文件等。

而Akka消息通信传递默认的容量最大为10M,一旦传递的消息超过这个限制就会出现这样的错误:

Worker任务失败后Master上会打印“Lost TID:”

根据这个信息找到对应的Worker节点后查看SparkHome/work/目录下的日志,查看Serialized size of result是否超过10M,就可以知道是不是Akka这边的问题了。

一旦确认是Akka通信容量限制之后,就可以通过配置spark.akka.frameSize控制Akka通信消息的最大容量。

2、Broadcast在调优场景的使用

Broadcast广播,主要是用于共享Spark每个Task都会用到的一些只读变量。

对于那些每个Task都会用到的变量来说,如果每个Task都为这些变量分配内存空间显然会使用很多多余的资源,使用广播可以有效的避免这个问题,广播之后,这些变量仅仅会在每台机器上保存一份,有Task需要使用时就到自己的机器上读取就ok。

官方推荐,Task大于20k时可以使用,可以在控制台上看Task的大小。

3、Collect结果过大的问题

大量数据时将数据存储在HDFS上或者其他,不是大量数据,但是超出Akka传输的Buffer大小,通过配置spark.akka.frameSize调整。

四、序列化与压缩

1、通过序列化手段优化

序列化之前说过,好处多多,所以是推荐能用就用,Spark上的序列化方式有几种,具体的可以参考官方文档。

这里只简单介绍一下Kryo。

配置参数的时候使用spark.serializer=”org.apache.spark.serializer.KryoSerializer”配置

自定义定义可以被Kryo序列化的类的步骤:

  1. 自定义类extends KryoRegistrator
  2. 设置序列化方式conf.set(“spark.serializer”,”org.apache.spark.serializer.KryoSerializer”)
  3. conf.set(“spark.kyro.registrator”,”自定义的class”)
  4. 如果对象占用空间大,需要增加Kryo的缓冲区则配置spark.kryoserializer.buffer.mb上值默认为2M

2、通过压缩手段优化

Spark的Job大致可以分为两种:

  • I/O密集型:即存在大量读取磁盘的操作。
  • CPU密集型:即存在大量的数据计算,使用CPU资源较多。

对于I/O密集型的Job,能压缩就压缩,因为读磁盘的时候数据压缩了,占用空间小了,读取速度不就快了。

对于CPU密集型的Job,看具体CPU使用情况再做决定,因为使用压缩是需要消耗一些CPU资源的,如果当前CPU已经超负荷了,再使用压缩反而适得其反。

Spark支持两种压缩算法:

  • LZF:高压缩比
  • Snappy:高速度

一些压缩相关的参数配置:

  1. spark.broadcast.compress:推荐为true
  2. spark.rdd.compress:默认为false,看情况配置,压缩花费一些时间,但是可以节省大量内存空间
  3. spark.io.compression.codec:org.apache.spark.io.LZFCompressionCodec根据情况选择压缩算法
  4. spark.io.compressions.snappy.block.size:设置Snappy压缩的块大小

五、其他优化方式

1、对外部资源的批处理操作

如操作数据库时,每个分区的数据应该一起执行一次批处理,而不是一条数据写一次,即map=>mapPartition。

2、reduce和reduceByKey

reduce:内部调用了runJob方法,是一个action操作。

reduceByKey:内部只是调用了combineBykey,是Transformation操作。

大量的数据操作时,reduce汇总所有数据到主节点会有性能瓶颈,将数据转换为Key-Value的形式使用reduceByKey实现逻辑,会做类似mr程序中的Combiner的操作,Transformation操作分布式进行。

3、Shuffle操作符的内存使用

使用会触发Shuffle过程的操作符时,操作的数据集合太大造成OOM,每个任务执行过程中会在各自的内存创建Hash表来进行数据分组。

可以解决的方案可能有:

  • 增加并行度即分区数可以适当解决问题
  • 可以将任务数量扩展到超过集群整体的CPU core数

Spark(十二)--性能调优篇的更多相关文章

  1. Android性能调优篇之探索垃圾回收机制

    开篇废话 如果我们想要进行内存优化的工作,还是需要了解一下,但这一块的知识属于纯理论的,有可能看起来会有点枯燥,我尽量把这一篇的内容按照一定的逻辑来走一遍.首先,我们为什么要学习垃圾回收的机制,我大概 ...

  2. Spark性能调优篇一之任务提交参数调整

    问题一:有哪些资源可以分配给spark作业使用? 答案:executor个数,cpu per exector(每个executor可使用的CPU个数),memory per exector(每个exe ...

  3. 阿里面试100%问到,JVM性能调优篇

    JVM 调优概述 性能定义 吞吐量 - 指不考虑 GC 引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标. 延迟 - 其度量标准是缩短由于垃圾啊收集引起的停顿时间或者完全消除因垃圾收集 ...

  4. 性能优化 | JVM性能调优篇——来自阿里P7的经验总结

    VM 调优概述: 性能定义: 吞吐量 - 指不考虑 GC 引起的停顿时间或内存消耗,垃圾收集器能支撑应用达到的最高性能指标. 延迟 - 其度量标准是缩短由于垃圾啊收集引起的停顿时间或者完全消除因垃圾收 ...

  5. Hive(十二)【调优】

    目录 1.Fetch抓取 2.本地模式 3.表的优化 3.1大小表join 3.2大表Join大表 3.3map join 3.4group By 3.5 count(distinct) 3.6笛卡尔 ...

  6. spark sql 的性能调优

    Caching Data in Memory 其他调优参数

  7. Spark性能调优篇二之重构RDD架构及RDD持久化

    如果一个RDD在两个地方用到,就持久化他.不然第二次用到他时,会再次计算. 直接调用cache()或者presist()方法对指定的RDD进行缓存(持久化)操作,同时在方法中指定缓存的策略. 原文:h ...

  8. Spark性能调优篇八之shuffle调优

    1 task的内存缓冲调节参数 2 reduce端聚合内存占比 spark.shuffle.file.buffer                     map task的内存缓冲调节参数,默认是3 ...

  9. Spark性能调优篇七之JVM相关参数调整

    降低cache操作的内存占比 方案: 通过SparkConf.set("spark.storage.memoryFraction","0.6")来设定.默认是0 ...

随机推荐

  1. python使用递归实现一个分形图形

    代码如下: import turtle def main(): t = turtle.Turtle() t.hideturtle() t.speed(10) level = 12 fract(t,-8 ...

  2. jQueryUI常用功能实战

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  3. HDU 4031 Attack

    Attack Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) Total Sub ...

  4. layer.confirm 询问框 的层遮盖

    function admin_del(obj) { layer.confirm('确认要重启吗?', { btn : [ '确定', '取消' ]//按钮 }, function(index) { l ...

  5. nginx源码学习 资料

    首先要做的当然是下载一份nginx源码,可以从nginx官方网站下载一份最新的. 看了nginx源码,发现这是一份完全没有注释,完全没有配置文档的代码. 现在你最希望要的是一份注释版的nginx源码, ...

  6. 使用jQuery和Bootstrap实现多层、自适应模态窗口

    本篇实践一个多层模态窗口,而且是自适应的. 点击页面上的一个按钮,弹出第一层自适应模态窗口. 在第一层模态窗口内包含一个按钮,点击该按钮弹出第二层模态窗口,弹出的第二层模态窗口会挡住第一层模态窗口,即 ...

  7. 委托、Lambda表达式、事件系列07,使用EventHandler委托

    谈到事件注册,EventHandler是最常用的. EventHandler是一个委托,接收2个形参.sender是指事件的发起者,e代表事件参数. □ 使用EventHandler实现猜拳游戏 使用 ...

  8. Java进程线程理解

    一个进程包括由操作系统分配的内存空间,包含一个或多个线程.一个线程不能独立的存在,它必须是进程的一部分.一个进程一直运行,直到所有的非守护线程都结束运行后才能结束. 多线程能满足程序员编写高效率的程序 ...

  9. WordPress基础:常用分类列表wp_list_categories

    函数:wp_list_categories($args) 作用:列出某个分类下的分类项目 用法: <ul> <?php $args= array( 'depth'=>1, 'o ...

  10. webrtc fec

    转自:http://www.cnblogs.com/webrtc/p/7402570.html WebRTC::FEC [TOC] Tags: WebRTC FEC WebRTC中的 FEC 实现分为 ...