Spark优化点

Spark为什么要使用累加器与广播变量

累加器
使用Accumulator时,为了保证准确性,只使用一次action操作。如果需要使用多次则使用cache或persist操作切断依赖。
例:val blankLines = sc.accumulator(0)//创建Accumulator[Int]并初始化为0
因为Spark是分布式的系统 变量的定义实在Driver端 ,但是在做累加操作的时候是运行在Executor中 也就是Worker端中,运行之后并没有把结果返回给Driver端,所以输出变量值就会还是之前定义的。使用累加器的话就会将运行在Driver所在服务器的Executor中。
广播变量
Spark程序是运行在Executor中的Task任务中,一个Executor中有多个Task在并行或者并发执行的,对于一个变量来说如果给每一个Task任务都分发一份那么就会造成资源浪费。如果将这个变量设为广播变量则只会给每一个Executor分发一份,减少了资源消耗。

Job,Stage,Task关系

Job可以简单的理解为提交的Spark程序,在程序中一个action算子划分为一个job。
Stage是Job的组成单位,通过宽依赖进行区分。一个Job可能包含1到多个Stage。
1个Stage可以有多个Task,一般来说,一个 rdd 有多少个 partition,就会有多少个 task,因为每一个 task 只是处理一个 partition 上的数据,可以并行计算。

并行度设置

设置合理的并行度可以有效提高spark任务的并行度。
并行度设置可以在SparkConf设置了spark.default.parallelism = num,或者在创建rdd的时候指定分区数量,建议将并行度设置为executor(x)的数量和每个executor的core(y)数的乘积的2-3倍。
因为可以同时并行计算Task的数量为xy,但是每个Task的执行时间并不是相同的 因此如果设置的并行度为xy的话 如果有的Task先执行结束,那么资源就会等待最慢的Task执行结束才会执行下一轮,造成了资源的浪费,因此建议设置问2xy-3xy这样即使有的Task提前执行结束也会有Task立即补上运行,充分利用资源。

尽可能的复用同一个RDD
将多次使用的RDD持久化

将RDD持久化避免不必要的计算,此外如果要保证在RDD的持久化数据可能丢失的情况下,还要保证高性能,那么可以对RDD进行checkpoint操作。

避免使用Shuffle类算子,使用高性能算子

mappartitions(),foreachpartitions(),aggrate().combine(),aggreateByKey()算子等。

使用kryo优化序列化性能

在Spark中,主要有三个地方涉及到了序列化:

  • 在算子函数中使用到外部变量时,该变量会被序列化后进行网络传输
  • 将自定义的类型作为RDD的泛型类型时(比如JavaRDD、Student是自定义类型),所有自定义类型对象,都会进行序列化。因此这种情况下,也要求自定义的类必须实现Serializable接口。
  • 使用可序列化的持久化策略时(比如MEMORY_ONLY_SER),Spark会将RDD中的每个partition都序列化成一个大的字节数组。
    Spark默认是使用java序列化机制但是性能不高,kryo序列化机制性能是java的10倍以上。
    kryo序列化使用需要注册。
val conf = new SparkConf().setMaster(...).setAppName(...)
// 设置序列化器为KryoSerializer。
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
// 注册要序列化的自定义类型。
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))
使用序列化持节性级别

如果内存不是特别充足的情况下,可以使用MEMORY_ONLY_SER或者MEMORY_AND_DISK_SER对RDD持久化序列化之后,RDD的每一个Partition的数据都是序列化为一个巨大的字节数组,这样,对于内存的消耗就小多了,但是唯一缺点是获取RDD的数据需要反序列化,会增大其CPU性能开销

Shuffle性能优化
  • spark.shuffle.consolidateFiles:是否开启shuffle block file的合并,默认为false
    减少了节点生成Shuffle BlockFile的文件数量,并且Result Task拉取数据的文件也减少了,所以减少了磁盘I/O的开销
  • spark.reducer.maxSizeInFlight:reduce task的拉取缓存,默认48m 可以适当调大
    Result Task每次只能从文件拉取指定缓存大小的数据量,拉取完之后进行聚合处理,然后再次拉取,如果内存足够大,可以稍微加大一些,拉取的次数就变少了
  • spark.shuffle.file.buffer:map task的写磁盘缓存,默认32k 可以适当调大
    Map端再将数据写入磁盘文件之前,会先把数据刷到叫做bucket缓存,然后达到一定数据量,再往ShuffleMapFile里面写,这样适当提高可以减少磁盘写的次数
  • spark.shuffle.memoryFraction:用于reduce端聚合的内存比例,默认0.2,超过比例就会溢出到磁盘上 可以适当调大
    执行Reduce Task的Executor有一部分内存用来汇聚各个Reduce Task拉取的的数据,放入map进行聚合,这个参数就表示用于这部分聚合的内存比是多少。如果数据量太大,内存不够用就会溢写到磁盘。可以适当的提高。
优化Executor内存比例

Spark默认对于每个Executor的内存的60%存放RDD缓存,40%的内存存放Task运行时创建的对象。
很可能在创建一个较大的内存对象时会因为40%的内存不足造成GC,在极端条件下会造成频繁的GC。
因此需要调优 SparkConf().set(“spark.storage.memoryFraction”, “0.5”)即可,可以将RDD缓存占用空间的比例降低,从而给更多的空间让task创建的对象进行使用。

因此Executor的内存主要分为三块:第一块是让task执行我们自己编写的代码时使用,默认是占Executor总内存的20%;第二块是让task通过shuffle过程拉取了上一个stage的task的输出后,进行聚合等操作时使用,默认也是占Executor总内存的20%;第三块是让RDD持久化时使用,默认占Executor总内存的60%。

SPARK数据倾斜处理

在这里插入图片描述

美团性能优化

Spark性能优化-基础篇
Spark性能优化-高级篇

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值