1. 概述
本文关键解说MaxCompute Spark资源调优,目的在于在保证Spark义务反常运转的前提下,指点用户更好地对Spark作业资源经常使用启动提升,极大化应用资源,降落老本。
Sensor提供了一种可视化的方式监控运转中的Spark进程,每个worker(Executor)及master(Driver)都具备各自的形态监控图,可以经过Logview中找到入口,如下图所示:
关上Sensor之后,可以看到下图提供了Driver/Executor在其生命周期内的CPU和内存的经常使用状况:cpu_plan/mem_plan(蓝线)代表了用户放开的CPU和内存方案量
用户可以直观地从cpu_usage图中看出义务运转中的CPU应用率mem_usage代表了义务运转中的内存经常使用,是mem_rss和page cache两项之和,详见下文
Memory Metrics
mem_rss 代表了进程所占用了常驻内存,这局部内存也就是Spark义务运转所经常使用的实践内存,通常要求用户关注,假设该内存超越用户放开的内存量,就或许会出现OOM,造成Driver/Executor进程中断。此外,该曲线也可以用于指点用户启动内存提升,假设实践经常使用量远远小于用户放开量,则可以增加内存放开,极大化应用资源,降落老本。
mem_cache(page_cache)用于将磁盘中的数据缓存到内存中,从而增加磁盘I/O操作,通常由系统启动治理,假设物理机内存短缺,那么mem_cache或许会经常使用很多,用户可以不用关心该内存的调配和回收。
3. 资源参数调优
(1)Executor Cores
相关参数:spark.executor.cores每个Executor的核数,即每个Executor中的可同时运转的task数目Spark义务的最大并行度是num-executors * executor-coresSpark义务口头的时刻,一个CPU core同一期间最多只能口头一个Task。假设CPU core数量比拟短缺,通常来说,可以比拟极速和高效地口头完这些Task。同时也要留意,每个Executor的内存是多个Task共享的,假设单个Executor核数太多,内存过少,那么也很或许出现OOM。
(2)Executor Num
相关参数:spark.executor.instances该参数用于设置Spark作业总共要用多少个Executor进程来口头通罕用户可以依据义务复杂度来选择究竟要求放开多少个Executor此外,要求留意,假设出现Executor磁盘空间无余,或许局部Executor OOM的疑问,可以经过增加单个Executor的cores数,参与Executor的instances数量来保证义务总体并行度不变,同时降落义务失败的危险。
(3)Executor Memory
相关参数:spark.executor.memory该参数用于设置每个Executor进程的内存。Executor内存的大小,很多时刻直接选择了Spark作业的性能,而且JVM OOM在Executor中更为经常出现。相关参数2:spark.executor.memoryOverhead设置放开Executor的堆外内存,关键用于JVM自身,字符串, NIO Buffer等开支,留意memoryOverhead 这局部内存并不是用来启动计算的,用户代码及spark都无法直接操作。假设不设置该值,那么默以为spark.executor.memory * 0.10,最小为384 MBExecutor 内存无余的体现方式:在Executor的日志(Logview->某个Worker->StdErr)中出现Cannot allocate memory
在义务完结的Logview result的第一行中出现:The job has been killed by "OOM Killer", please check your job's memory usage.
在Sensor中发现内存经常使用率十分高
在Executor的日志中出现java.lang.OutOfMemoryError: Java heap space在Executor的日志中出现GC overhead limit exceeded
Spark UI中发现频繁的GC消息或许出现OOM的直接体现方式:局部Executor出现No route to host: workerd********* / Could not find CoarseGrainedScheduler等失误或许要素及处置方案:限度executor 并行度,将cores 调小:多个同时运转的 Task 会共享一个Executor 的内存,使得单个 Task 可经常使用的内存增加,调小并行度能缓解内存压力参与单个Executor内存参与分区数量,增加每个executor负载思考数据歪斜疑问,由于数据歪斜造成某个 task 内存无余,其它 task 内存足够假设出现了上文所述的Cannot allocate memory或The job has been killed by "OOM Killer", please check your job's memory usage,这种状况通常是由于系统内存无余,可以适当参与一些堆外内存来缓解内存压力,通常设置spark.executor.memoryOverhead为1g/2g就足够了
(4)Driver Cores
相关参数spark.driver.cores通常Driver Cores不要求太大,然而假设义务较为复杂(如Stage及Task数量过多)或许Executor数量过多(Driver要求与每个Executor通讯并坚持心跳),在Sensor中看到Cpu应用率十分高,那么或许要求适当调大Driver Cores另外要留意,在Yarn-Cluster形式运转Spark义务,不能直接在代码中设置Driver的资源性能(core/memory),由于在JVM启动时就要求该参数,因此要求经过--driver-memory命令行选项或在spark-defaults.conf文件/Dataworks性能项中启动设置。
(5)Driver Memory
相关参数1:spark.driver.memory设置放开Driver的堆内内存,与executor相似相关参数2:spark.driver.maxResultSize代表每个Spark的action(例如collect)的结果总大小的限度,默以为1g。假设总大小超越此限度,作业将被中止,假设该值较高或许会造成Driver出现OOM,因此用户要求依据作业实践状况设置适当值。相关参数3:spark.driver.memoryOverhead设置放开Driver的堆外内存,与executor相似Driver的内存通常不要求太大,假设Driver出现内存无余,通常是由于Driver搜集了过多的数据,假设要求经常使用collect算子将RDD的数据所有拉取到Driver上启动处置,那么必定确保Driver的内存足够大。体现方式:
Spark运行程序无照应或许直接中止在Driver的日志(Logview->Master->StdErr)中发现了Driver OutOfMemory的失误Spark UI中发现频繁的GC消息在Sensor中发现内存经常使用率十分高在Driver的日志中出现Cannot allocate memory
或许要素及处置方案:代码或许经常使用了collect操作将过大的数据集搜集到Driver节点在代码创立了过大的数组,或许加载过大的数据集到Driver进程汇总SparkContext,DAGScheduler都是运转在Driver端的。对应rdd的Stage切分也是在Driver端运转,假设用户自己写的程序有过多的步骤,切分出过多的Stage,这局部消息消耗的是Driver的内存,这个时刻就要求调大Driver的内存。有时刻假设stage过多,Driver端甚至会有栈溢出
(6)本地磁盘空间
相关参数:spark.hadoop.odps.cupid.disk.driver.device_size:该参数代表为单个Driver或Executor放开的磁盘空间大小,自动值为20g,最大允许100gShuffle数据以及BlockManager溢出的数据均存储在磁盘上
磁盘空间无余的体现方式:在Executor/Driver的日志中发现了No space left on device失误
处置方案:
最便捷的方法是直接参与更多的磁盘空间,调大spark.hadoop.odps.cupid.disk.driver.device_size假设参与到100g之后依然出现该失误,或许是由于存在数据歪斜,shuffle或许cache环节中数据集中散布在某些block,也或许是单个Executor的shuffle数据量确实过大,可以尝试:
对数据重分区,处置数据歪斜疑问
增加单个Executor的义务并发spark.executor.cores
增加读表并发spark.hadoop.odps.input.split.size
参与executor的数量spark.executor.instances
要求留意:
雷同由于在JVM启动前就要求挂载磁盘,因此该参数必定性能在spark-defaults.conf文件或许dataworks的性能项中,不能性能在用户代码中此外要求留意该参数的单位为g,不能省略g很多时刻由于用户性能位置有误或许没有带单位g,造成参数实践并没有失效,义务运转依然失败
4. 总结
上文关键引见了MaxCompute Spark在经常使用环节中或许遇到的资源无余的疑问及相应的处置思绪,为了能够最大化应用资源,首先倡导依照1: 4的比例来放开单个worker资源,即1 core: 4 gb memory,假设出现OOM,那么要求检查日志及Sensor对疑问启动初步定位,再启动相应的提升和资源调整。不倡导单个Executor Cores 设置过多,通常单个Executor在2-8 core是相对安保的,假设超越8,那么倡导参与instance数量。适当参与堆外内存(为系统预留一些内存资源)也是一个罕用的调优方法,通常在通常中可以处置很多OOM的疑问。最后,用户可以参考官网文档,蕴含更多的内存调优技巧,如gc提升,数据序列化等。