spark-submit参数设置说明,即提交EMR集群的Spark作业资源调优,详见该链接:spark-submit 参数设置说明 和该链接:Spark On YARN内存和CPU分配。
AM: YARN Application Master
RM: Resource Manager
NM: Node Manager
1、YARN可分配资源
YARN的RM负责管理整个集群,NM则负责管理该工作节点。
YARN的NM可分配core数(即可以分给Container的最大CPU核数)由参数yarn.nodemanager.resource.cpu-vcores
指定,一般要小于本节点的物理CPU核数,因为要预留一些资源给其他任务。Hadoop集群工作节点一般都是同构的,即配置相同。NM可分配给Container的最大内存则由参数yarn.nodemanager.resource.memory-mb
指定,默认情况下,可分配内存会小于本机内存*0.8
。
注意,分配给作业的资源不要超过YARN可分配的集群资源总数。注意:分配给单个Container的核数和内存不能超过阈值,即为Executor设置的核数和内存不能超过阈值。若分配给作业的资源超过上限,将不会启动指定数目的Executor(也就是说,不会起足够数目的Container)。
2、YARN的部署模式
spark-submit脚本设置参数 => 配置Spark作业。
--deploy-mode有两个可选值,分别是“client”和“cluster”。
若为client,则Driver进程会在Master主节点运行。
若为cluster,则Driver会随机在某个从节点上启动运行。
不管是client还是cluster,作业的AM都会在某个从节点上运行,都会占用一个Container。
client模式下,默认情况,这个Container会占用1核1G的资源。
具体原因为,参数spark.yarn.am.cores
指定AM使用的core数目,默认值为1。参数spark.yarn.am.memory
指定AM占用的内存,默认值为512M,而在参数spark.yarn.am.memoryOverhead
的加持之下,分配给AM的内存会在设定值上溢出384M或10%
(取大值),而由于参数yarn.scheduler.increment-allocation-mb
指定YARN分配资源给Container时,内存增长的步长,默认为1024MB。综上,client模式下,YARN为AM使用的Container默认分配1核1G的资源。
cluster模式下,AM使用的Container占用的资源由--driver-memory
和--driver-cpu
指定,且会受到参数spark.yarn.driver.memoryOverhead
和yarn.scheduler.increment-allocation-mb
的加持。
由AM向RM申请资源,若集群资源足够,RM会尽量满足要求,给一些Container。
然后就会在Container里起Executor。
运行Spark Application时,依然是Driver分发任务给Executor执行。
3、资源使用的优化
若要运行大作业,想要使用更多的集群资源,选择client部署模式。
在Spark on YARN模式下,Spark在给Driver(client模式下,Driver会在Master节点运行,故不会多分配内存;cluster模式下,会给Driver多分配一些内存)和Executor分配内存时,会在用户设定的内存值上溢出 384M 或 10%(取大值,spark 2.2.1版本里,见参数spark.yarn.executor.memoryOverhead
和spark.yarn.driver.memoryOverhead
)。
YARN在给Container分配内存时(Driver或者Executor均在Container中运行),遵循向上取整的原则(由参数yarn.scheduler.increment-allocation-mb
指定YARN分配资源给Container时,内存增长的步长,默认值为1024M ),所以实际分配的内存为1G的整数倍。
原则上,计算出来的作业使用资源只要不超过集群总资源即可。但是实际场景中,操作系统、HDFS和EMR服务等都需要使用core和mem资源,所以如果把资源全部分给作业,会导致性能下降,甚至无法运行。
另外,分配给作业的core数目一般也会被设置成略小于集群的可使用核(英特尔的处理器常为4核8线程、8核16线程或16核32线程等),因为设置太多(设置的分区数为core数目的整数倍),会频繁调度切换在CPU之上运行的任务,性能并不会提高。具体情况,应该在作业运行的时候,观察一下集群从节点CPU的利用率。
事实上,YARN默认可分配内存只有不到集群总内存的80%,我们在指定内存的时候,Spark会多给它们分配一些内存,并且Container的内存增长步长固定,于是就显得YARN给Container分配的内存是1G的整数倍。而且,每台机器需要留一个core给其他任务,并且集群要留一个core给AM。
4、一些配置建议
(1)如果Executor内存设置过大,GC时会导致长时间的暂停,建议分配的内存<=64G
。
(2)如果数据源为OSS,则建议将Executor分到不同的ECS上,这样可以将每一个ECS的带宽都用上。例如我只有三个从节点,则--num-executors=3
,并设置合理的并发(即core数目)和内存。
(3)如果作业里使用了非线程安全的代码,如果多线程并行执行任务会导致作业不正常,则建议设置--executor-cores=1
。
5、EMR控制台实际作业配置情况
--master yarn
--deploy-mode client
--class com.service.app.main.class
--conf spark.memory.fraction=0.3
--conf spark.serializer=org.apache.spark.serializer.KryoSerializer
--conf spark.eventLog.enabled=false
--driver-memory 2g
--num-executors 3
--executor-cores 6
--executor-memory 9g
ossref://what-bucket-name/path/to/APP.jar