Spark 调优
开发调优
1、 提高RDD 的使用效率
对于同一份数据,应该只创建一个 RDD
尽可能复用RDD
对多次使用的RDD 持久化
cache算法进行缓存,但是同时也要 unPersist进行释放
2、 合理使用数据结构
对应 Java 提供的一些高级数据结构或者Scala提供的一些高级数据结构,其内部都是按照对象进行存储和实现的,每个对象都有对象头、引用等额外信息,比较占用空间。
如 HashMap, String 等。
避免使用这些高级数据结构浪费内存。使用原始类型(int 、 Long 替代字符串),使用数组替代集合类型,这样尽可能减少内存占用,降低GC 频率,提升性能。
3、 任务并行度
提高任务的并行度,更有效率的使用CPU 资源; 比如利用 textFile()、 parallelize() 等方法的第二个参数来设置并行度;
也可以使用 spark.default.parallelism 参数,并设置统一的并行度,给集群中的每个CPU CORE 设置2~3个 task。
4、小文件合并
以Hdfs 为例: hdfs 以Block 为单位 进行MR 作业,在Spark中是partition的概念。小文件过多导致Task会很多,每个核处理的批次变多,从而性能下降,因此在读取数据时
对小文件进行合并是很有必要。
直接使用 textFile,在参数里写明Partition个数,但是这个方式有局限,数据量多少一般无法获知,设置的partition多少不知道,另外设置这个参数也是读取完数据调用
重分区方法分区的;
直接使用 textFile,然后调用 rePartition方法重分区
5、 Driver 内存合理使用
减少RDD 直接 collect 、print 操作。
利用 take().collect() 或者 first() 代替
6、 使用高性能算子、尽量避免使用 shuffle 类算子
尽可能避免使用 reduceByKey、join、distinct、repartitiion 等会进行shuffle算子,尽量使用map类的非 shuffle算子
1、reduceByKey/aggregateByKey 替代 groupByKey
本地聚合和传输聚合的区别
2、mapPartition 替换 map
map面向数据的每一条,partition 面向一个block。
3、filter+coalesce 减少 Task
过滤后,调整partition,从而减少Task数量,提高运算效率。
4、foreachPartitions替代 foreach
执行批量插入操作
7、广播变量的使用
可以将小表或者配置参数广播到每个Executor的内存中,在Task处理时直接从内存中读取,不用再远程拉取数据。
大表关联小表
算法参数或者外部小变量
map + broadCast 取代 join
8、使用Kryo优化序列化性能
在算子函数中使用到外部变量时,该变量会被序列化后进行网络传输
所有自定义类型对象
使用可序列化的持久策略
资源调优
对Spark运行过程中各个使用资源的地方,通过调节各种参数来优化使用效率。
1、 executor 配置
spark.executor.memory
spark.executor.instances
spark.executor.cores
2、 driver 配置
spark.driver.memory
spark.driver.cores
3、并行度
spark.default.parallelism(used for RDD API)
spark.sql.shuffle.partitions(used for DataFrame/DataSet API)
4、网络超时
spark.network.timeout(所有网络交互的默认超时)
数据倾斜调优
数据倾斜是指在一份数据中,部分Key由于占据了整体数据的90%的内容,所以在进shuffle,发生数据
倾斜的Key会处理很长时间,导致整个任务执行很长时间。数据倾斜可能由于系统出现故障,导致一类数据很多,也可能是业务的数据本来就是如此。在进行shuffle的时候,此时如果某个Key对应的数据量特别大的话,就会发生数据倾斜;如果分区处理的数据过大,也可以认为数据倾斜。
解决方案:
1、查找热点数据
如RDD.countByKey()、RDD.takeSample().countByKey()
2、使用Hive ETL 预处理数据
3、过滤少数导致倾斜的 key
4、提高shuffle 操作的并行度
5、采样倾斜key并 拆分 join操作
6、分段聚合
解决思路: 先试用count 算子或者采样sample 算子找出发生倾斜的 Key,把这部分数据过滤出来;
对这部分Key设计打乱Key算子,比如进行flatMap操作中,随机生成 0-500这样的数字,或者随机数字+一定的字符串,只要是能容器区分就行,然后再这给Key随机加上,具体的随机范围可配置;然后把第二部分的rdd和第一部分经过过滤剩下的 rdd 进行 union,然后在进行数据倾斜要进行的 shuffle处理,这样的数据就基本不倾斜了;处理完后,再把第二部分做个 map操作,把随机生成的 key处理掉。