Spark on Yarn资源配置

2019-05-15 11:31:33 浏览数 (1)

工作期间,我提交spark任务到yarn上,发现指定的资源(使用内存大小。使用core的个数)总是与yarn的UI页面显示的资源使用量不一致,写本文说明一下这个问题,以及介绍一下spark on yarn的资源配置。

以下是我的yarn集群各节点的物理资源:

总共6个节点,每个节点的物理内存为16G、物理core个数为4个,考虑到要给其他应用或者系统进程预留一些资源,所以我设置yarn集群的每个节点使用12GB物理内存和8个虚拟核。

这里有虚拟核的概念,我个人的理解是,yarn集群默认可以使用集群中的全部物理核,每个节点有4个物理核,而我配置每个NodeManager节点可以使用8个虚拟核,这就说明在我的集群上,一个物理核=两个虚拟核,而假如我设置一个节点可以使用12个虚拟核,则在我的集群中,一个物理核=三个虚拟核。

配置如下:

capacity-scheduler.xml

代码语言:javascript复制
<property>
    <name>yarn.scheduler.capacity.resource-calculator</name>
    <value>org.apache.hadoop.yarn.util.resource.DominantResourceCalculator</value>
    <description>DefaultResourceCalculator只能计算内存相关的信息,DominantResourceCalculator可以统计core和内存的信息</description>
</property>

yarn-site.xml

代码语言:javascript复制
<property>
    <name>yarn.nodemanager.resource.memory-mb</name>
    <value>12288</value>
    <description>每个NodeManager可以使用的物理内存为12G</description>
</property>

<property>
    <name>yarn.nodemanager.resource.cpu-vcores</name>
    <value>8</value>
    <description>每个NodeManager可以使用的虚拟CPU为8</description>
</property>

以上配置生效后,yarn集群可用的内存为12GB * 6 = 72GB,可用虚拟core个数为 8 * 6 = 48,重启yarn集群查看资源:

这里与我的预期一致。

下面配置一些Container相关的资源:

yarn-site.xml

代码语言:javascript复制
<property>
    <name>yarn.scheduler.minimum-allocation-mb</name>
    <value>1024</value>
    <description>每个Container最少可以都要分配1G内存</description>
</property>

<property>
    <name>yarn.scheduler.maximum-allocation-mb</name>
    <value>12288</value>
    <description>每个Container最多可以使用12G内存,这意味着如果某个Container启动后占用了12G即NodeManager可以使用的全部内存后,在该NodeManager上将无法再启动任何一个Container</description>
</property>

<property>
    <name>yarn.scheduler.minimum-allocation-vcores</name>
    <value>1</value>
    <description>每个Container最少可以使用1个虚拟CPU</description>
</property>

<property>
    <name>yarn.scheduler.maximum-allocation-vcores</name>
    <value>8</value>
    <description>每个Container最多可以使用8个虚拟CPU</description>
</property>

<property>
    <name>yarn.scheduler.increment-allocation-mb</name>
    <value>1024</value>
    <description>内存规整化单位,意味着分配给某个Container的内存一定是1024即1G的倍数,例如某个Container实际需要1.5G内存,那么就给它2G</description>
</property>

<property>
    <name>yarn.nodemanager.vmem-pmem-ratio</name>
    <value>2.1</value>
    <description>NodeManager每使用1单位的物理内存,就会使用2.1倍的虚拟内存,例如NodeManager使用了1G物理内存,那么表现为虚拟内存是2.1G,当分配的虚拟内存大于的物理内存的2.1倍后,抛出异常</description>
</property>

配置好yarn的基本资源使用信息后,我尝试提交了一个spark任务:

代码语言:javascript复制
$SPARK_HOME/bin/spark-submit 
--class com.bonc.rdpe.spark.test.yarn.WordCount 
--master yarn 
--deploy-mode client 
--conf spark.yarn.am.memory=512m  # ApplicationMaster可以使用的内存
--conf spark.yarn.am.cores=2  # ApplicationMaster可以使用的虚拟CPU
--conf spark.executor.memory=1g  # 每个executor可以使用的内存
--conf spark.executor.cores=4  # 每个executor可以使用的虚拟CPU
--conf spark.executor.instances=6  # 启动Executor的个数
./spark-test-1.0.jar

任务运行后yarn UI显示:

可以看到:

  • 总共启动了7个Container,其中1个Container用于启动ApplicationMaster,其他6个Container用于启动Executor
  • 一共使用了26个vcore,因为我们指定ApplicationMaster使用2个vocre,启动了6个Executor,每个使用4个vcore,所以总共使用的vcore数是:2 6 * 4 = 26
  • 一共使用了13G内存,其中ApplicationMaster使用了1G,6个Executor使用了6 * 2G = 12G

分析一下为什么实际分配的内存会比申请的要多:

  • ApplicationMaster申请512M内存,分配的时候除了这512M内存,还会多余分配堆外内存用于额外开销,分配的堆外内存的量为 max(${spark.yarn.am.memory} * 0.1, 384) = max(51.2M, 384M) = 384M,于是应该分配给ApplicationMaster 512(程序申请) 384(系统分配的堆外内存) = 896M内存, 而实际分配的内存量还要在此基础上做规整,yarn-site.xml中的这个配置 yarn.scheduler.increment-allocation-mb=1024(默认),这个值的意思是:实际分配的内存应该是这个值的整数倍,于是896M又被提升为1024M,即1G,因此,实际给ApplicationMaster分配了1G内存
  • 对于Executor而言,它申请1G内存,多余分配的用于额外开销的堆外内存为 max(${spark.executor.memory} * 0.1, 384) = (102.4M, 384M) = 384M 于是应该分配 1024 384 = 1408M,规整为1024的整数倍后,就成了2G

当然你可以自己配置ApplicationMaster和Executor使用的堆外内存量,当用户自定义后,就不会再用以上的公式去计算堆外内存的大小。

接下说一下spark on yarn怎么配置资源。

(1) 配置ApplicationMaster使用的堆外内存

  • Client模式:spark.yarn.am.memoryOverhead
  • Cluster模式:spark.driver.memoryOverhead

(2) 配置Executor使用的堆外内存 Client和Cluster模式用同一个参数:spark.executor.memoryOverhead

(3) 设置 ApplicationMaster 使用的内存

  • Client:spark.yarn.am.memory
  • Cluster:spark.driver.memory 或者 --driver-memory

(4) 设置 ApplicationMaster 使用的vcore

  • Client:spark.yarn.am.cores
  • Cluster:spark.driver.cores 或者 --driver-cores

(5) 设置 Executor使用的内存(Client和Cluster通用): spark.executor.memory或者--executor-memory

(6) 设置 Executor使用的vcore(Client和Cluster通用): spark.executor.cores或者--executor-cores

(7) 设置启动 Executor的个数(Client和Cluster通用): spark.executor.instances或者--num-executors

有了以上的内容的铺垫,我们可以改变提交命令的参数,并自行计算实际分配的资源,然后启动程序做验证。

测试:

代码语言:javascript复制
$SPARK_HOME/bin/spark-submit 
--class com.bonc.rdpe.spark.test.yarn.WordCount 
--master yarn 
--deploy-mode cluster 
--driver-memory 1g 
--driver-cores 4 
--executor-memory 2g 
--executor-cores 2 
--num-executors 4 
--conf spark.driver.memoryOverhead=1g 
--conf spark.executor.memoryOverhead=1g 
./spark-test-1.0.jar

预测资源使用情况:

可以预测:

  • 启动5个Container,一个用于启动 ApplicationMaster,其他4个用于启动 Executor
  • ApplicationMaster使用vcore:4
  • ApplicationMaster使用内存1g 1g,不需要规整,总共2g
  • 每个Executor使用vcore:2
  • 每个Executor使用内存2g 1g,不需要规整,总共3g
  • 实际配置资源量:vcore:4 4 * 2 = 12,内存:2g 4 * 3g = 14g

和预计资源使用情况一致!

0 人点赞