Spark代码,参数,数据倾斜调优

Spark调优

代码调优

1.避免创建重复的RDD
2.尽可能复用同一个RDD
3.对多次使用的RDD进行持久化
持久化策略选择:

  • 默认情况:MEMORY_ONLY(性能最高,前提内存足够,实际生产环境中也不可能把所有的内存提供给你进行持久化,数据量一大就会导致JVM的OOM(out-of-memory:内存溢出)
  • 若使用MEMORY_ONLY发生内存溢出,建议尝试MEMORY_ONLY_SER级别,降低了内存占用,比MEMORY_ONLY多出的开销主要是序列化与反序列化,总体性能还行,但问题和之前一样:当RDD中的数据量过大也还是会造成OOM异常
  • 如果纯内存的级别都无法使用,建议使用MEMORY_AND_DISK_SER(内存和磁盘序列化)策略,该策略会优 先尽量尝试将数据缓存在内存中,内存缓存不下才会写入磁盘
  • 不建议使用DISK_ONLY和后缀为_2的级别,完全基于磁盘性能骤降,_2会对数据复制一份副本然后发送给其它节点,导致网络传输开销(除非是要求作业的高可用性,否则不建议使用)

4.尽量避免使用shuffle类的算子
5.使用map-side预聚合的shuffle操作
5.使用高性能算子

  • reduceByKey(map端预聚合)替代groupByKey
  • mapPartitions替代普通map transformation算子
  • foreachPartitions代替foreach Action算子
  • filter之后进行coalese操作
  • repartition:coalesce(numPartitions,true) 增多分区使用这个
  • coalesce(numPartitions,false) 减少分区 没有shuffle只是合并 partition

6.广播大便量

  • 如果使用的外部变量比较大,建议使用Spark的广播功能,对该变量进行广播
  • 广播 后的变量,会保证每个Executor的内存中,只驻留一份变量副本,而Executor中的 task执行时共享该Executor中的那份变量副本。这样的话,可以大大减少变量副本 的数量,从而减少网络传输的性能开销,并减少对Executor内存的占用开销,降低 GC的频率

7.使用Kryo优化序列化性能

  • 在算子函数中使用到外部变量时
  • 将自定义的类型作为RDD的泛型类型时
  • 使用可序列化的持久化策略时

8.优化数据结构

  • 尽量使用字符串替代对象
  • 使用原始类型(比如 Int、Long)替代字符串
  • 使用数组替代集合类型
    9.使用高性能的库fastutil

参数调优

1.num-executors:设置Executos个数

  • 参数调优建议:每个Spark作业的运行一般设置50~100个左右的Executor进程比较合适,设置太少或太多的Executor进程都不好。设置的太少,无法充分利用集群资源;设置的太多的话,大部分队列可能无法给予充分的资源。

2.executor-memory:设置每个Executo的进程内存

  • 参数调优建议:每个Executor进程的内存设置4G~8G较为合适(只是建议,具体设置视情况而定)

3.executors-cores:设置每个Executor进程的CPU core数量

  • 参数调优建议:Executor的CPU core数量设置为2~4个较为合适

4.driver-memory:设置Driver进程的内存

  • 参数调优建议:Driver的内存通常来说不设置,或者设置1G左右应该就够了

5.spark.default.parallelism:设置每个stage的默认task数量

  • 参数调优建议:Spark作业的默认task数量为500~1000个较为合适

6.spark.storage.memoryFraction:设置RDD持久化数据在Executor内存中能占的比例,默认是0.6

  • 参数调优建议:如果Spark作业中,有较多的RDD持久化操作,该参数的值可以适当提高一些,保证持久化的数据能够容纳在内存中

7.spark.shuffle.memoryFraction:设置shuffle过程中一个task拉取到上个stage的task的输出后,进行聚合操作时能够使用的Executor内存的比例,默认是0.2

  • 参数调优建议:如果Spark作业中的RDD持久化操作较少,shuffle操作较多时,建议降低持久化操作的内存占比,提高shuffle操作的内存占比比例,避免shuffle过程中数据过多时内存不够用,必须溢写到磁盘上,降低了性能。
参数调优模板
spark-submit 
--class com.shujia.*.* 
--master yarn-cluster 
--num-executors 100   // 资源大小,数据量
--executor-memory 8G // 广播变量,cache数据量
--executor-cores 4  
--driver-memory 2G
--conf spark.default.parallelism=100 // shuffle之后rdd分区数
--conf spark.storage.memoryFraction=0.4 // rdd持久化内存占比
--conf spark.shuffle.memoryFraction=0.4 //rddshuffle内存占比
--conf spark.locality.wait=10 //task在Executor中的等待的超时时间
--conf spark.shuffle.file.buffer=64k
--conf spark.yarn.executor.memoryOverhead=2048M
--conf spark.network.timeout=600s


任务使用的资源
400C   800G

数据倾斜调优

1.使用Hive ETL预处理数据,从根源上解决数据倾斜(但是治标不治本,在ETL进行group by 和join等shuffle操作时还是会出现数据倾斜,只是把数据倾斜提前到了hive的ETL,避免出现在Spark后续处理)

  • 适用场景:如果导致数据倾斜的是Hive表。如果该Hive表中的数据本身很不均匀(比如某个 key对应了100万数据,其他key才对应了10条数据),而且业务场景需要频繁使用Spark对Hive表 执行某个分析操作

2.过滤少数导致数据倾斜的key

  • 适用场景:如果发现导致倾斜的key就少数几个,而且对计算本身的影响并不大的话,那么很 适合使用这种方案。比如99%的key就对应10条数据,但是只有一个key对应了100万数据,从而导 致了数据倾斜

3.提高shuffle操作的并行度

  • spark.sql.shuffle.partitions,该参数代表了shuffle read task的并行度,该值默认是200,对于很 多场景来说都有点过小

4.双重聚合

  • 适用场景:对RDD执行reduceByKey等聚合类shuffle算子或者在Spark SQL中使用group by 语句进行分组聚合时,比较适用这种方案
  • 第一次局部聚合,先给每个key 都附加上一个随机数变成不同的key,这样原本被一个task处理的key就被分散到多个task上去聚合了,解决了单个task处理数据量过多的问题
  • 第二次将各个key的随机前缀给去掉,再次 进行全局聚合操作

5.把reduce join转为map join

  • 适用场景:在对RDD使用join类操作,或者是在Spark SQL中使用join语句时,而且join操作中 的一个RDD或表的数据量比较小(比如几百M或者一两G)
  • 大小表join,广播小表

6.采样倾斜的key并拆分join操作

  • 适用场景:两个RDD/Hive表进行join的时候,如果数据量都比较大,无法采用“解决方案五 ”,那么此时可以看一下两个RDD/Hive表中的key分布情况。如果出现数据倾斜,是因为其中某一 个RDD/Hive表中的少数几个key的数据量过大,而另一个RDD/Hive表中的所有key都分布比较均匀
  • 大表1join大表1(其中大表1数据倾斜,大表2数据均匀分布)
  • 先拆分出大表1倾斜的key打上随机数,然后拆分出大表2和导致大表1倾斜的key相同的key进行join操作 ,把大表1和大表2剩下的key进行join操作,最后把两个join后的表进行union

7.使用随机前缀和扩容RDD进行join(不常用)

  • 适用场景:如果在进行join操作时,RDD中有大量的key导致数据倾斜,那么进行分拆key也没 什么意义

猜你喜欢

转载自blog.csdn.net/qq_43278189/article/details/121364538