spark最大的有点也是它最大的问题-----基于内存的计算模型
1、使用高性能序列化类库
Kryo类库序列化,比java的Serializable占用空间更小,通常比Java序列化的小10倍。
使用方法:SparkConf().set(“spark.serializer”,“org.apache.spark.serializer.KryoSerializer”)即可
2、优化数据结构
优先使用数组以及字符串而不是集合类
避免多层嵌套的结构
通常情况下,会将HashMap,List这种数据统一用String拼接成特殊格式的字符串
3、对多次使用的RDD进行持久化
4、使用序列化的持久化级别
5、java虚拟机垃圾回收机制
6、提高并行度
7、广播共享数据
例如在大表join小表,可以将小表通过broadcast广播出去
8、数据本地化
9、reduceByKey和groupByKey的合理使用,reducebykey会在map端先进行你自定义的function操作,可以减少IO,reduceByKey优先级更高
10、Shuffle调优
11、数据倾斜的处理 缓解/消除:
一、避免数据源的数据倾斜
①尽量避免数据源的数据倾斜,比如数据源是kafka,相关的topic和各parition之间的数据是否平衡,直接决定Spark处理该数据时是否会产生数据倾斜
②例如数据源是hive,而Hive表中的数据本身很不均匀,可以先对hive的源表进行预处理。这种思路是将数据倾斜提前到了hive的etl中,这种可以设置每天例如凌晨去执行一次然后每次再spark作业美团.点评的交互式用户行为分析系统使用了这种方案
二、调整并行度,分散同一个Task的不同Key
在对RDD执行shuffle算子时,给shuffle算子传入一个参数,比如reduceByKey(1000),该参数设置的shuffle read task的数量,对于Spark sql中的shuffle类的语句。可以设置spark.sql.shuffle.partitions,默认值是200,对于很多场景来说有点小
三、两阶段聚合
将原本相同的key通过附加随机前缀的方式变成多个不同的key,就可以让原本被一个task处理的数据分散到多个task上去做局部聚合,进而解决单个task处理数据量过多的问题,接着去掉随机前缀再进行全局聚合,仅仅适用于聚合类的shuffle操作
四、自定义partitioner
使用自定义的partitioner替换掉默认的hashpartitioner
优点:不影响原有的并行度设计,因为如果改变并行度后续stage的并行度也会默认改变,可能影响stage
缺点:只能将不同key分散开,但是对于同一key对应数据集非常大的场景不适用,而且需要根据数据特点自定义partitioner不够灵活
五、将reduce side join 转变为 map side join
在对RDD进行join或者spark sql join,如果一个rdd或者表的数据量不大,比如几百M或者1-2G
不使用join而是使用BroadCast变量与mao类算子实现join,这样可以避免shuffle操作。将较小RDD的数据通过collect算子拉取到Driver端的内存中,然后对其创建一个BradoCast变量
优点:效果很好
缺点:因为我们将小表广播出去,比较消耗内存资源,driver和每个executor内存中都会驻留一份小表的全量数据。因此只适合一大一小
6、Spark性能优化
最新推荐文章于 2023-03-02 22:53:22 发布