如果觉得这篇文章对您有帮助,别忘了点赞、分享或关注哦!您的一点小小支持,不仅能帮助更多人找到有价值的内容,还能鼓励我持续分享更多精彩的技术文章。感谢您的支持,让我们一起在技术的世界中不断进步!
Spark 性能调优
1. 资源配置
- Executor 配置 :合理配置
--num-executors
,--executor-memory
,--executor-cores
,Executor数量、内存、核数要根据工作负载进行调整,避免内存不足或过度分配。- Driver 配置 :设置
--driver-memory
来分配给 Driver 的内存,确保 Driver 能够处理所有的任务调度。2. 数据存储和格式
- 存储格式:选择合适的存储格式,推荐使用列式存储格式(如 Parquet 或 ORC),它们能有效压缩数据,并且支持快速查询。
- 分区策略 :合理地选择数据的分区策略,避免数据倾斜。使用
repartition
或coalesce
对 DataFrame 或 RDD 进行分区操作,使分区更均匀。- 数据压缩:使用合适的压缩算法(如 Snappy、Gzip 等)来减少存储空间和网络传输开销。
3. 并行度调整
- 任务并行度 :调整任务的并行度(例如,设置
spark.sql.shuffle.partitions
(调整 Shuffle read task并行度) 或spark.default.parallelism
(默认并行度)
),使任务能够合理分配到多个节点上,避免某些节点成为瓶颈。4. 广播变量
- 使用广播变量来避免大规模的数据重复传输,尤其是在需要和小表进行 join 操作时,避免小表重复发送给所有的 executor。
5. 使用Kryo序列化
- Spark默认使用 Java 的序列化机制,Java序列化机制的效率不高,序列化速度慢并且序列化后的数据所占用的空间依然较大,Kryo序列化更高效,能减少序列化数据的体积并提高速度
6. 调整本地化等待时长
- Spark 希望 task 能够运行在它要计算的数据算在的节点(数据本地化思想),这样就可以避免数据的网络传输,
- Spark会等待一段时间,默认 3s,如果等待指定时间后仍然无法在指定节点运行,那么会自动降级,尝试将 task 分配到比较差的本地化级别所对应的节点上
- 本地化等级分为:PROCESS_LOCAL(性能最好)、NODE_LOCAL、RACK_LOCA、NO_PREF、ANY
- 设置代码如下:val conf = new SparkConf().set("spark.locality.wait", "6s")
7. 算子调优
- mapPartition算子替代map算子,如果某个分区数据量过大,容易导致 OOM,因此需谨慎使用。
- foreachPartition算子替代foreach算子,通常用于完成数据库的写入,此算子可以减少资源初始化开销,但同样要注意分区数据量过大可能导致OOM。
- reduceByKey算子替代groupByKey算子,reduceByKey会进行局部combine操作,可减少shuffle时传输的数据量。
- 使用repartition算子与coalesce算子重分区,repartition 会触发 shuffle 操作,适用于增大分区数;coalesce 仅在减少分区数时适用,且不会触发 shuffle,适合在分区数差距较小的情况下使用。
- 避免使用collect操作,collect操作会将数据拉取到driver端,数据量较大时会导致OOM。
8. shuffle调优
- 调节map算缓冲区大小,默认为32KB,代码设置:val conf = new SparkConf().set("spark.shuffle.file.buffer", "64"),增加缓冲区大小,缓解频繁溢写
- 调节reduce端拉取数据缓冲区大小,默认为48MB,代码设置:val conf = new SparkConf() .set("spark.reducer.maxSizeInFlight",
"96"),增加缓冲区带下,减少拉取数据的次数,减少网络传输,提升性能。- 调节SortShuffleManager排序操作的阈值,默认值为200,代码设置:val conf = new SparkConf().set("spark.shuffle.sort.bypassMergeThreshold",
"400"),shuffle write 过程中不会进行排序操作,减少了排序的性能开销。9. 缓存和持久化
- RDD 缓存 :对于需要多次访问的数据,可以使用
cache
或persist
将数据缓存到内存中,避免重复计算。- 合适的持久化级别 :根据内存和计算需求,选择合适的持久化级别,如
MEMORY_ONLY
或MEMORY_AND_DISK
,来平衡内存使用和磁盘 IO。10. 日志和监控
- 合理的日志级别 :设置合理的日志级别(例如使用
INFO
或WARN
),避免日志过多影响性能。- Spark UI 监控:通过 Spark UI 监控作业执行情况,识别性能瓶颈,如任务执行时间过长、shuffle 操作过多等。