为啥 Spark 每个执行器只使用一个核心?它如何决定使用分区数量以外的核心?

Posted

技术标签:

【中文标题】为啥 Spark 每个执行器只使用一个核心?它如何决定使用分区数量以外的核心?【英文标题】:Why Spark utilizing only one core per executor? How it decides to utilize cores other than number of partitions?为什么 Spark 每个执行器只使用一个核心?它如何决定使用分区数量以外的核心? 【发布时间】:2017-04-27 21:23:48 【问题描述】:

我在 HPC 环境中使用 Spark 独立模式 spark 版本 1.6.1 在 slurm 上运行 spark。问题是我的 slurm 节点没有在 spark 独立模式下完全使用。我在我的 slurm 脚本中使用 spark-submit。一个节点上有 16 个内核可用,正如我在 SPARK UI 上看到的那样,每个执行程序都有 16 个内核。但实际上每个执行器只使用了一个核心。执行器进程正在运行的工作节点上的 top + 1 命令显示 16 个 cpu 中只有一个 cpu 正在使用。我有 255 个分区,所以分区在这里似乎不是问题。

$SPARK_HOME/bin/spark-submit \
            --class se.uu.farmbio.vs.examples.DockerWithML \
            --master spark://$MASTER:7077 \
            --executor-memory 120G \
            --driver-memory 10G \

当我将脚本更改为

$SPARK_HOME/bin/spark-submit \
            --class se.uu.farmbio.vs.examples.DockerWithML \
            --master local[*] \
            --executor-memory 120G \
            --driver-memory 10G \

我在 Spark UI 上看到为执行程序分配了 0 个内核,这是可以理解的,因为我们不再使用 spark 独立集群模式。但是现在当我在工作节点上检查 top + 1 命令时,所有内核都被使用了,这暗示问题不在于应用程序代码,而在于 spark 独立模式对资源的利用。

那么当 spark 有 16 个内核并且有足够的分区时,它是如何决定每个执行程序使用一个内核的呢?我可以更改什么以便它可以利用所有内核?

我正在使用spark-on-slurm 来启动这些作业。

两种情况下的 Spark 配置都是闲置的:

--master spark://MASTER:7077

(spark.app.name,DockerWithML)                       
(spark.jars,file:/proj/b2015245/bin/spark-vs/vs.examples/target/vs.examples-0.0.1-jar-with-dependencies.jar)                        
(spark.app.id,app-20170427153813-0000)                      
(spark.executor.memory,120G)                        
(spark.executor.id,driver)                      
(spark.driver.memory,10G)                       
(spark.history.fs.logDirectory,/proj/b2015245/nobackup/eventLogging/)                       
(spark.externalBlockStore.folderName,spark-75831ca4-1a8b-4364-839e-b035dcf1428d)                        
(spark.driver.maxResultSize,2g)                     
(spark.executorEnv.OE_LICENSE,/scratch/10230979/SureChEMBL/oe_license.txt)                      
(spark.driver.port,34379)                       
(spark.submit.deployMode,client)                        
(spark.driver.host,x.x.x.124)                       
(spark.master,spark://m124.uppmax.uu.se:7077)

--master local[*]

(spark.app.name,DockerWithML)                                   
(spark.app.id,local-1493296508581)                                  
(spark.externalBlockStore.folderName,spark-4098cf14-abad-4453-89cd-3ce3603872f8)                                    
(spark.jars,file:/proj/b2015245/bin/spark-vs/vs.examples/target/vs.examples-0.0.1-jar-with-dependencies.jar)                                    
(spark.driver.maxResultSize,2g)                                 
(spark.master,local[*])                                 
(spark.executor.id,driver)                                  
(spark.submit.deployMode,client)                                    
(spark.driver.memory,10G)                                   
(spark.driver.host,x.x.x.124)                                   
(spark.history.fs.logDirectory,/proj/b2015245/nobackup/eventLogging/)                                   
(spark.executorEnv.OE_LICENSE,/scratch/10230648/SureChEMBL/oe_license.txt)                                  
(spark.driver.port,36008)

谢谢,

【问题讨论】:

你在做什么样的工作?数据源是什么?有些作业不可并行化,有些数据源(如压缩文件)最初无法分区。 该应用程序是可并行化的,并且在云环境中运行良好。由于云上的资源较少,我不得不迁移到 HPC。并且文件没有被压缩,它们是带有分子的 SDF 文件。 【参考方案1】:

问题是您只有一个工作节点。在 spark 独立模式下,每个工作实例启动一个执行程序。要启动多个逻辑工作者实例以便在物理工作者中启动多个执行器,您需要配置此属性: SPARK_WORKER_INSTANCES

默认情况下,它设置为 1。您可以根据您在代码中进行的计算相应地增加它,以利用您拥有的资源量。

您希望将您的工作分配给执行器以正确利用资源,但发生的情况是只有一个执行器正在启动,它无法利用您拥有的核心数量和内存量。所以,你没有得到火花分布式计算的味道。

您可以设置 SPARK_WORKER_INSTANCES = 5 并为每个执行器分配 2 个核心;因此,10 个核心将被正确利用。 像这样,您调整配置以获得最佳性能。

【讨论】:

【参考方案2】:

尝试设置 spark.executor.cores(默认值为 1)

根据 Spark 文档:

每个执行器上使用的核心数。仅适用于 YARN 和独立模式。在独立模式下,设置此参数允许应用程序在同一个工作程序上运行多个执行程序,前提是该工作程序上有足够的核心。否则,每个应用程序只能在每个工作人员上运行一个执行程序。

见https://spark.apache.org/docs/latest/configuration.html

【讨论】:

对于 1.6.1 版本,它表示全部处于独立模式,但我仍然会尝试。 spark.apache.org/docs/1.6.1/configuration.html 我玩过 spark.executor.cores 它可以让我制作更多的执行器,例如我在一个节点上有 16 个内核。如果我将此 var 设置为 5,那么我会得到 3 个执行器,每个执行器有 5 个核心。但是当我看到 top 时,有 3 个 java 调用使用了大约 33% 并且 top + 1 显示只有 CPU1 正在使用,其余 15 个 CPU 根本没有使用。 你说得对,在 1.6.1 中这个属性应该没用。您能否提供有关如何启动独立集群的更多信息?您在 executors 选项卡的 web ui(端口 8080)上看到了什么? 在执行器选项卡上,我有一个执行器和一个驱动程序。执行程序一次处理 16 个任务,但 RDD Blocks 为 0,当我将版本更改为 spark 1.6.3 时,RDD 块为 2。我想在这里补充一下,我没有使用 hdfs 进行阅读和写作。我正在使用 HPC 系统附带的共享存储。【参考方案3】:

在 spark 集群模式下,您应该使用命令 --num-executor "numb_tot_cores*num_of_nodes"。例如,如果您有 3 个节点,每个节点有 8 个核心,您应该编写 --num-executors 24

【讨论】:

以上是关于为啥 Spark 每个执行器只使用一个核心?它如何决定使用分区数量以外的核心?的主要内容,如果未能解决你的问题,请参考以下文章

Apache Spark 如何将分区 ID 分配给其执行程序

为啥运行不成功 spark

为啥我只看到分阶段的 200 个任务?

Spark 与执行者和核心数量的关系

Spark 独立数量执行器/核心控制

为啥我导入 numpy 后多处理只使用一个核心?