spark性能优化

1.分配资源,并行度,rdd架构与缓存

2.shuffle调优

3.spark算子调优

4.jvm调优,广播大变量。。。

 

 

 

 

1:分配更多的资源

  分配那些资源?

 excutor ,cpu  per ececuter,memory  per  executer

 在哪里分配资源?

 在提交spark提交作业的脚步中,提交参数

 调节到多大算是最大呢?

为什么调节了资源之后,性能可以提升?

 

2:调节并行度

并行度设置成CPU数据的2-3倍,通过新建spark上下文设置参数

如何设置一个Spark Application的并行度?

spark.default.parallelism

SparkConf conf = new SparkConf()

  .set("spark.default.parallelism", "500")

 

3:重构RDD已经RDD持久化

3.1.rdd架构重构与优化

  尽量去复用rdd,差不多的rdd,可以抽取成一个共同的rdd,供后面的rdd计算时,反复的使用

3.2.公共的rdd 一定要持久化

3.3.持久化是可以序列化的 (正常数据持久化,可能导致内存过大)

内存不够时,首先可以序列化后存在内存中-获取数据时需要反序列化

OOM  内存溢出

优先  内存

      内存+序列化

其次  考虑 内存+磁盘的方式

最次的  是  内存+磁盘 +序列化

 

3.4.为了数据的可靠性  可以是用双副本机制。

把持久化的每个副本单元 存在其他节点,一个副本丢失,不需要重新计算

资源很充足

 

4:广播大变量

5.实际羡慕中使用kryo序列化

SparkConf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")

 

首先第一步,在SparkConf中设置一个属性,spark.serializer,org.apache.spark.serializer.KryoSerializer类;

 

Kryo之所以没有被作为默认的序列化类库的原因,就要出现了:主要是因为Kryo要求,如果要达到它的最佳性能的话,那么就一定要注册你自定义的类(比如,你的算子函数中使用到了外部自定义类型的对象变量,这时,就要求必须注册你的类,否则Kryo达不到最佳性能)。

 

第二步,注册你使用到的,需要通过Kryo序列化的,一些自定义类,SparkConf.registerKryoClasses()

 

项目中的使用:

.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")

.registerKryoClasses(new Class[]{CategorySortKey.class})

 

 

 

6.在实际项目中使用fastutil优化数据格式

 

7.在实际项目中调节数据本地化等待时长.

数据本地化级别

PROCESS_LOCAL:进程本地化,代码和数据在同一个进程中,也就是在同一个executor中;计算数据的task由executor执行,数据在executor的BlockManager中;性能最好

NODE_LOCAL:节点本地化,代码和数据在同一个节点中;比如说,数据作为一个HDFS block块,就在节点上,而task在节点上某个executor中运行;或者是,数据和task在一个节点上的不同executor中;数据需要在进程间进行传输

NO_PREF:对于task来说,数据从哪里获取都一样,没有好坏之分

RACK_LOCAL:机架本地化,数据和task在一个机架的两个节点上;数据需要通过网络在节点之间进行传输

ANY:数据和task可能在集群中的任何地方,而且不在一个机架中,性能最差

 

spark.locality.wait,默认是3s

 

 

8.JVM调优之原理概述以及降低cache操作的内存占比

spark.storage.memoryFraction,0.6 -> 0.5 -> 0.4 -> 0.2

 

 

 

9.用户访问session分析JVM调优之调节executor堆外内存与连接等待时长

 

调节executor堆外内存

--conf spark.yarn.executor.memoryOverhead=2048

spark-submit脚本里面,去用--conf的方式,去添加配置;一定要注意

 

连接等待时长

--conf spark.core.connection.ack.wait.timeout=300

 

 

10.Shuffle调优之合并map端输出文件

new SparkConf().set("spark.shuffle.consolidateFiles", "true")

开启shuffle map端输出文件合并的机制;默认情况下,是不开启的,就是会发生如上所述的大量map端输出文件的操作,严重影响性能。

 

 

11.Shuffle调优之调节map端内存缓冲与reduce端内存占比

调优:

 

调节map task内存缓冲:spark.shuffle.file.buffer,默认32k(spark 1.3.x不是这个参数,后面还有一个后缀,kb;spark 1.5.x以后,变了,就是现在这个参数)

调节reduce端聚合内存占比:spark.shuffle.memoryFraction,0.2

 

在实际生产环境中,我们在什么时候来调节两个参数?

看Spark UI,如果你的公司是决定采用standalone模式,那么狠简单,你的spark跑起来,会显示一个Spark UI的地址,4040的端口,进去看,依次点击进去,可以看到,你的每个stage的详情,有哪些executor,有哪些task,每个task的shuffle write和shuffle read的量,shuffle的磁盘和内存,读写的数据量;如果是用的yarn模式来提交,课程最前面,从yarn的界面进去,点击对应的application,进入Spark UI,查看详情。

 

如果发现shuffle 磁盘的write和read,很大。这个时候,就意味着最好调节一些shuffle的参数。进行调优。首先当然是考虑开启map端输出文件合并机制。

 

调节上面说的那两个参数。调节的时候的原则。spark.shuffle.file.buffer,每次扩大一倍,然后看看效果,64,128;spark.shuffle.memoryFraction,每次提高0.1,看看效果。

 

不能调节的太大,太大了以后过犹不及,因为内存资源是有限的,你这里调节的太大了,其他环节的内存使用就会有问题了。

 

调节了以后,效果?map task内存缓冲变大了,减少spill到磁盘文件的次数;reduce端聚合内存变大了,减少spill到磁盘的次数,而且减少了后面聚合读取磁盘文件的数量。

 

12.Shuffle调优之HashShuffleManager与SortShuffleManager

spark.shuffle.manager:hash、sort、tungsten-sort(自己实现内存管理)

spark.shuffle.sort.bypassMergeThreshold:200

 

 

大家理解的更加深入了。hash、sort、tungsten-sort。如何来选择?

 

1、需不需要数据默认就让spark给你进行排序?就好像mapreduce,默认就是有按照key的排序。如果不需要的话,其实还是建议搭建就使用最基本的HashShuffleManager,因为最开始就是考虑的是不排序,换取高性能;

 

2、什么时候需要用sort shuffle manager?如果你需要你的那些数据按key排序了,那么就选择这种吧,而且要注意,reduce task的数量应该是超过200的,这样sort、merge(多个文件合并成一个)的机制,才能生效把。但是这里要注意,你一定要自己考量一下,有没有必要在shuffle的过程中,就做这个事情,毕竟对性能是有影响的。

 

3、如果你不需要排序,而且你希望你的每个task输出的文件最终是会合并成一份的,你自己认为可以减少性能开销;可以去调节bypassMergeThreshold这个阈值,比如你的reduce task数量是500,默认阈值是200,所以默认还是会进行sort和直接merge的;可以将阈值调节成550,不会进行sort,按照hash的做法,每个reduce task创建一份输出文件,最后合并成一份文件。(一定要提醒大家,这个参数,其实我们通常不会在生产环境里去使用,也没有经过验证说,这样的方式,到底有多少性能的提升)

 

4、如果你想选用sort based shuffle manager,而且你们公司的spark版本比较高,是1.5.x版本的,那么可以考虑去尝试使用tungsten-sort shuffle manager。看看性能的提升与稳定性怎么样。

 

总结:

1、在生产环境中,不建议大家贸然使用第三点和第四点:

2、如果你不想要你的数据在shuffle时排序,那么就自己设置一下,用hash shuffle manager。

3、如果你的确是需要你的数据在shuffle时进行排序的,那么就默认不用动,默认就是sort shuffle manager;或者是什么?如果你压根儿不care是否排序这个事儿,那么就默认让他就是sort的。调节一些其他的参数(consolidation机制)。(80%,都是用这种)

 

spark.shuffle.manager:hash、sort、tungsten-sort

 

new SparkConf().set("spark.shuffle.manager", "hash")

new SparkConf().set("spark.shuffle.manager", "tungsten-sort")

 

// 默认就是,new SparkConf().set("spark.shuffle.manager", "sort")

new SparkConf().set("spark.shuffle.sort.bypassMergeThreshold", "550")

 

 

13.算子调优之filter过后使用coalesce减少分区数量

 

14.算子调优之使用foreachPartition优化写数据库性能

正式生产环境中一般都是是foreachPartition进行数据的的写操作,一次性操作一个分片的数据

但是一个分片的数据量特别大时,可能会导致OOM

 

 

15.算子调优之使用repartition解决Spark SQL低并行度的性能问题

spark SQL 并不能设置并行度,通过repartition进行重新分区

 

通常情况下 设置 spark.default.parallelism  设置并行度

 

16.算子调优之reduceByKey本地聚合 的特性

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值