我正在尝试最大化群集使用以完成一项简单的任务 .
Cluster是1 2 x m3.xlarge,运行Spark 1.3.1,Hadoop 2.4,Amazon AMI 3.7
该任务读取文本文件的所有行并将其解析为csv .
当我将任务作为纱线群集模式提交时,我得到以下结果之一:
-
0 executor:job无限等待,直到我手动杀死它
-
1执行人:仅使用1台机器工作的资源利用资源
当我没有为驱动程序分配足够的内存时 -
OOM
我期待的是:
- Spark驱动程序在集群主服务器上运行,所有可用内存,以及2个执行程序,每个执行程序9404MB(由install-spark脚本定义) .
有时,当我使用1个执行程序执行“成功”执行时,克隆并重新启动该步骤最终会有0个执行程序 .
我使用此命令创建了我的集群:
aws emr --region us-east-1 create-cluster --name "Spark Test"
--ec2-attributes KeyName=mykey
--ami-version 3.7.0
--use-default-roles
--instance-type m3.xlarge
--instance-count 3
--log-uri s3://mybucket/logs/
--bootstrap-actions Path=s3://support.elasticmapreduce/spark/install-spark,Args=["-x"]
--steps Name=Sample,Jar=s3://elasticmapreduce/libs/script-runner/script-runner.jar,Args=[/home/hadoop/spark/bin/spark-submit,--master,yarn,--deploy-mode,cluster,--class,my.sample.spark.Sample,s3://mybucket/test/sample_2.10-1.0.0-SNAPSHOT-shaded.jar,s3://mybucket/data/],ActionOnFailure=CONTINUE
有一些步骤变化,包括:
--driver-memory 8G --driver-cores 4 --num-executors 2
使用-x的install-spark脚本生成以下spark-defaults.conf:
$ cat spark-defaults.conf
spark.eventLog.enabled false
spark.executor.extraJavaOptions -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:MaxHeapFreeRatio=70
spark.driver.extraJavaOptions -Dspark.driver.log.level=INFO
spark.executor.instances 2
spark.executor.cores 4
spark.executor.memory 9404M
spark.default.parallelism 8
Update 1
我使用通用JavaWordCount示例获得相同的行为:
/home/hadoop/spark/bin/spark-submit --verbose --master yarn --deploy-mode cluster --driver-memory 8G --class org.apache.spark.examples.JavaWordCount /home/hadoop/spark/lib/spark-examples-1.3.1-hadoop2.4.0.jar s3://mybucket/data/
但是,如果我删除'--driver-memory 8G',任务将被分配2个执行程序并正确完成 .
那么,驱动程序内存阻止我的任务获取执行程序的问题是什么?
是否应该在集群的主节点上与Yarn主容器一起执行驱动程序,如here所述?
如何为我的火花作业驱动程序提供更多内存? (如果出现收集和其他一些有用的操作)
4 回答
最大化群集使用的解决方案是在EMR上安装spark并在手动调整执行程序内存和内核时忘记'-x'参数 .
这个post给出了一个很好的解释,说明在YARN上运行Spark时如何完成资源分配 .
要记住的一件重要事情是所有执行者必须分配相同的资源!正如我们所说,Spark不支持异构执行程序 . (目前正在进行一些支持GPU的工作,但这是另一个主题)
因此,为了在为执行程序最大化内存的同时获得分配给驱动程序的最大内存,我应该像这样分割我的节点(这个slideshare在第25页提供了很好的截图):
节点0 - 主(纱线资源管理器)
节点1 - NodeManager(容器(驱动程序)容器(Executor))
节点2 - NodeManager(容器( Actuator )容器( Actuator ))
注意:另一个选项是
spark-submit
与主节点0的--master yarn --deploy-mode client
. 有任何反例这是一个坏主意吗?在我的例子中,我最多可以拥有2个vcore的3个 Actuator ,每个4736 MB具有相同规格的驱动程序 .
4736内存源自
/home/hadoop/conf/yarn-site.xml
中定义的yarn.nodemanager.resource.memory-mb
的值 . 在m3.xlarge上,它设置为11520 mb(对于与每个实例类型关联的所有值,请参阅here)然后,我们得到:
(11520 - 1024)/ 2(每个节点的执行程序)= 5248 => 5120(向下舍入为yarn.scheduler.minimum-allocation-mb中定义的256 mb增量)
7% * 5120 = 367舍入到384(内存开销) will become 10% in spark 1.4
5120 - 384 = 4736
其他有趣的链接:
Apache Spark: setting executor instances does not change the executors
Performance issues for spark on YARN
http://www.wdong.org/wordpress/blog/2015/01/08/spark-on-yarn-where-have-all-my-memory-gone/
问题在于对Spark如何在YARN上工作的期望 . 当部署模式为cluster或master设置为yarn-cluster运行Spark时,驱动程序不会在主节点上执行,而是在其中一个从属节点上的Application Master容器中执行 . 有关详细信息,请参阅https://spark.apache.org/docs/latest/running-on-yarn.html
我希望发生的事情是集群无法满足驱动程序的内存要求(请记住,实际请求集群的内存是您要求的内存加上开销),因此永远等待分配应用程序主机的驱动程序将运行或为遗嘱执行人 .
要为驱动程序提供您请求的内存量,您需要使用其他从属服务器,以便同时为基于群集的驱动程序和执行程序提供资源 . 由于驱动程序的开销,我怀疑您可能需要使用具有更多内存的实例类型 . 当您为驱动程序请求8G时,请查看资源管理器日志并验证请求的实际数量 .
要在主节点上运行驱动程序,部署模式需要是客户端 . 如果您使用一步调用脚本将驱动程序jar本地化到主节点上,然后下一步可以调用spark-submit,那么仍可以使用EMR步骤完成此操作设置为部署模式客户端并在本地主文件系统上引用JAR .
Michel Lemay的帖子是很好的背景阅读,他给出了一个特定群集配置的答案 . 我已将该逻辑嵌入到电子表格中,该电子表格将显示任何群集的最佳选项 . 要使用,请填写群集中的节点数,虚拟核心/节点数以及可分配内存/节点数 . 执行此操作后,工作表将为您提供启动命令的选项,这些命令将完全利用您的群集进行客户端和群集模式,以便为每个节点分别执行1,2,4和8个执行程序 . 我已经突出显示了每个节点对应2个执行程序的行,因为这一直是我测试中的最佳选择 . 您可以根据需要随意复制此工作表或添加不同群集类型的选项卡 .
https://docs.google.com/spreadsheets/d/1VH7Qly308hoRPu5VoLIg0ceolrzen-nBktRFkXHRrY4/edit?usp=sharing
以下是我解决问题的方法:
通过将spark.executor.memory驱动程序内存设置为低于任何给定MASTER节点的总和,YARN能够将主服务器和执行程序放置在给定节点上 . 您牺牲了其他节点上的一些丢失内存,但其更多重要的是我有CPU运行 . 这是一个例子(在r3.8xlarge上):