Spark性能调优
executor内存不足
- 问题表现1:Container xx is running beyond physical memory limits. Current usage: xxx GB of x GB physical memory used; xx GB of x GB virtual memory used…
原因:这个报错显而易见,数据使用的内存超过了这个executor分配的内存 - 问题表现2:长时间的 Fail to get RpcResponse: Timeout,最后会报heartbeat心跳检测失败而任务失败
原因:实际上同样是因为内存不足,导致GC而超时,最终失败
解决:
1 首先可以尝试开大executor的内存分配
2 如果配置的内存无法满足数据内存,可以尝试:
2.1 增加大数据量位置的repartition数
val allDf = sourceDf
.repartition(5000)
.flatMap(row => { }).toDF()
2.2 增加spark session的超时时间
val ss = SparkSession.builder()
.config("spark.sql.shuffle.partitions", 1000)
.config("spark.driver.maxResultSize", "20g")
.config("hive.exec.dynamic.partition", true)
.config("hive.exec.dynamic.partition.mode", "nonstrict")
.config("hive.exec.parallel", true)
.config("mapred.max.split.size", 64000000)
.config("mapred.min.split.size.per.node", 64000000)
.config("mapred.min.split.size.per.rack", 64000000)
.config("hive.exec.reducers.bytes.per.reducer", 256000000)
.config("hive.exec.reducers.max", 2000)
.config("hive.merge.mapredfiles", true)
.config("hive.merge.smallfiles.avgsize", 128000000)
.config("hive.merge.size.per.task", 128000000)
.config("spark.yarn.executor.memoryOverhead", "10g")
.config("spark.network.timeout", 10000000) // 调大
.enableHiveSupport()
.getOrCreate()
GC overhead limit exceeded
executor报错:
java.lang.OutOfMemoryError: GC overhead limit exceeded
错误表明JVM花费了太多时间(默认是98%)来回收很少的内存(默认是2%),并且这种情况持续了很长时间。这通常是因为堆内存(Heap)太小,无法容纳应用程序的内存需求,或者是因为内存泄漏。
解决方案
- 增加 Executor 内存: 在提交 Spark 作业时,可以通过 --executor-memory 或在 Spark 配置文件中设置 spark.executor.memory 来增加每个 Executor 的内存大小。例如,将 Executor 内存增加到 8G:
spark-submit --executor-memory 8g ...
或在配置文件中:
spark.executor.memory=8g
- 增加堆外内存(Off-Heap Memory): 如果已经增加了堆内存但问题仍然存在,可以考虑使用堆外内存。通过设置 spark.executor.memoryOverhead,可以为每个 Executor 分配额外的堆外内存。例如,分配 1G 堆外内存:
spark.executor.memoryOverhead=1024
- 优化垃圾回收: 调整垃圾回收器的设置可能有助于减少 GC 的开销。例如,使用 G1 垃圾回收器替代默认的垃圾回收器。可以通过设置 spark.executor.extraJavaOptions 来调整:
spark.executor.extraJavaOptions=-XX:+UseG1GC
-
减少数据倾斜: 数据倾斜可能导致某些 Executor 需要处理比其他 Executor 更多的数据,从而增加内存压力。通过重新分区或使用 Spark 的高级功能(如 salting)来减少数据倾斜。
-
优化 Spark 应用程序:
- 减少不必要的数据缓存
- 使用更高效的数据结构
- 避免在单个大对象上操作,尽可能分解成小对象处理。
-
调整 GC 配置: 如果 GC 开销过高,可以尝试调整 GC 相关参数,例如增加 GC 线程数,调整堆区大小等。这需要对 JVM 的垃圾回收机制有一定了解。
用UNION ALL
代替UNION
UNION会默认对两个表的结果进行去重,如果没有去重的需要,就使用UNION ALL,速度会更快
persist与耗时监控
在主流程的对运算结果调用处persist,并打点进行耗时监控。而不是在运算方法内部persist,便于看清每一步的运算时间。
用OR替换UNION ALL
UNION ALL 操作会消耗大量的内存和CPU,如果可能,尽量减少使用。在这个查询中,你可以尝试将三个 UNION ALL 的查询合并为一个,使用 OR 条件来替代。