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

本篇记录了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. BZOJ4277 : [ONTAK2015]Cięcie

    假设分成如下三段: [1..i][i+1..j][j+1..n] 考虑中间那一段,设f[i]为前i位组成的数模q的值,pow[i]为$10^i$模q的值,那么有: f[j]-f[i]*pow[j-i] ...

  2. MongoDB数组修改器更新数据(转)

    MongoDB数组修改器更新数据    这里,我们将了解一下数组修改器.数组,是我们经常看到和使用到的且非常有用的数据结构:它不仅可以通过索进行引用,还可以作为集合来使用.数组修改器,顾名思义,它是用 ...

  3. java 虚拟机启动参数 (转)

    在Java.J2EE大型应用中,JVM非标准参数的配置直接关系到整个系统的性能. JVM非标准参数指的是JVM底层的一些配置参数,这些参数在一般开发中默认即可,不需要任何配置.但是在生产环境中,为了提 ...

  4. WebConfig 加密解密的原理是什么?

    WebConfig 加密解密的原理是什么? 使用命令 加密数据连接串 加密:aspnet_regiis -pef connectionStrings d:/...(webconfig所在路径,不能含中 ...

  5. swap文件查看

    建议 Swap 使用单独的分区: a swap file a combination of swap partitions and swap files. Swap 大小的计算公式: M 等于物理内存 ...

  6. linux内核数据包转发流程(二):中断

    [版权声明:转载请保留出处:blog.csdn.net/gentleliu.邮箱:shallnew*163.com] 内核在处理2层数据包之前,必须先处理中断系统.设立中断系统,才有可能每秒处理成千的 ...

  7. MyEclipse使用总结——设置MyEclipse使用的Tomcat服务器

    一.设置使用的Tomcat服务器 如果不想使用MyEclipse自带的tomcat服务器版本,那么可以在MyEclipse中设置我们自己安装好的tomcat服务器 设置步骤如下: Window→Pre ...

  8. 在ASP.NET MVC中通过勾选checkbox来更改select的内容

    遇到了这样的一个需求:通过勾选checkbox来更改select的内容. 在没有勾选checkbox之前是这样的: 在勾选checkbox之后是这样的: 想通过ajax异步来实现.所以,从控制器拿到的 ...

  9. C#编程(二十九)----------泛型接口

    泛型接口 定义 先来看一个简单的例子: public class Sharp {} public class Rectangle:Sharp {} 上面定义了两个简单的类,一个是图形类,一个是矩形类; ...

  10. i386、i586、i686、noarch、x86_64

    xxxxxxxxx.rpm   <== RPM的格式,已经经过编译且包装完成的rpm文件. xxxxxx.src.rpm   <== SRPM的格式,包含未编译的源代码信息. 例如rp-p ...