Apache Spark:内核数量与执行程序数量


192

我试图了解在YARN上运行Spark作业时内核数与执行程序数之间的关系。

测试环境如下:

  • 数据节点数:3
  • 数据节点机器规格:
    • CPU:Core i7-4790(内核数:4,线程数:8)
    • 内存:32GB(8GB x 4)
    • 硬盘:8TB(2TB x 4)
  • 网络:1Gb

  • Spark版本:1.0.0

  • Hadoop版本:2.4.0(Hortonworks HDP 2.1)

  • Spark作业流程:sc.textFile->过滤器->映射->过滤器-> mapToPair-> reduceByKey->映射-> saveAsTextFile

  • 输入数据

    • 类型:单个文本文件
    • 大小:165GB
    • 线数:454,568,833
  • 输出量

    • 第二个过滤器之后的行数:310,640,717
    • 结果文件的行数:99,848,268
    • 结果文件的大小:41GB

该作业使用以下配置运行:

  1. --master yarn-client --executor-memory 19G --executor-cores 7 --num-executors 3 (每个数据节点的执行程序,使用的内核数最多)

  2. --master yarn-client --executor-memory 19G --executor-cores 4 --num-executors 3 (减少的内核数)

  3. --master yarn-client --executor-memory 4G --executor-cores 2 --num-executors 12 (更少的核心,更多的执行者)

经过时间:

  1. 50分15秒

  2. 55分48秒

  3. 31分23秒

令我惊讶的是,(3)快得多。
我认为(1)会更快,因为在改组时执行者之间的交流会更少。
尽管(1)的核心数少于(3),但是#of的核心数不是关键因素,因为2)表现良好。

(在pwilmot的回答之后添加了以下内容。)

有关此信息,性能监视器的屏幕截图如下:

  • (1)的Ganglia数据节点摘要-作业始于04:37。

(1)的Ganglia数据节点摘要

  • (3)的Ganglia数据节点摘要-作业始于19:47。在此之前,请忽略该图。

(3)的Ganglia数据节点摘要

该图大致分为2个部分:

  • 第一:从头到尾还原ByKey:CPU密集型,无网络活动
  • 第二:reduceByKey:CPU降低之后,网络I / O完成。

如图所示,(1)可以使用给定的CPU能力。因此,这可能不是线程数的问题。

如何解释这个结果?


2
现在我怀疑是GC ...实际上,在Spark UI上,GC花费的总时间在1)上比2)上更长。
zeodtr 2014年

您为什么不尝试3)19G?将工作人员限制在4G上是否会降低某些人所拥有的NUMA效应?也就是说,您的4G位于分配给您的工作流程的2个核心之一上,因此I / O速度降低了,从而提高了整体性能。否则,我认为一个主要问题是:在一个工作者上可以使用一个执行程序有多少个内核/线程?(一个人只能指定一个工人的内核总数,而不能指定执行者的粒度)
Bacon

4
顺便说一句,我刚刚检查了core / src / main / scala / org / apache / spark / deploy / worker / ExecutorRunner.scala上的代码,看来1个执行者= 1个工人线程。
培根

有点晚了,但是这是有关此主题的cloudera
2015年

1
顺便说一下,我在cloudera幻灯片平台slideshare.net/cloudera/…中找到了此信息,这部分解释了执行者,核心和内存中的决定因素
Manish Sahni

Answers:


58

为了使所有这些更加具体,下面是一个配置Spark应用程序以使用尽可能多的集群的工作示例:想象一个集群,其中有六个运行NodeManager的节点,每个节点配备16个内核和64GB内存。NodeManager的yarn.nodemanager.resource.memory-mb和yarn.nodemanager.resource.cpu-vcores容量应分别设置为63 * 1024 = 64512(兆字节)和15。我们避免将100%的资源分配给YARN容器,因为该节点需要一些资源来运行OS和Hadoop守护程序。在这种情况下,我们为这些系统进程保留了一个千兆字节和一个内核。Cloudera Manager通过考虑这些因素并自动配置这些YARN属性来提供帮助。

可能的第一个冲动是使用--num-executors 6 --executor-cores 15 --executor-memory 63G。但是,这是错误的方法,因为:

63GB +执行程序的内存开销不适合NodeManagers的63GB容量。应用程序主节点将在其中一个节点上占用一个核心,这意味着该节点上没有容纳15个核心执行程序的空间。每个执行程序15个内核可能会导致HDFS I / O吞吐量下降。

更好的选择是使用--num-executors 17 --executor-cores 5 --executor-memory 19G。为什么?

此配置会导致除具有AM的一个节点外的所有节点上的三个执行器,后者将具有两个执行器。--executor-memory的推导为(每个节点63/3个执行器)=21。21* 0.07 = 1.47。21 – 1.47〜19。

Cloudera博客中的一篇文章“ 如何做:调整Apache Spark作业(第2部分)”中给出了解释


1
“此配置将在所有节点上导致三个执行器,除了带有AM的一个执行器之外,它将有两个执行器。” 对于“ --executor-cores 5”,这意味着什么?
derek

这意味着每个执行者使用5个核心。每个节点有3个执行程序,因此使用15个核心,除了其中一个节点还将运行该作业的应用程序主控器,因此只能托管2个执行程序,即10个核心用作执行程序。
达沃斯

很好地说明-请注意,这适用于yarn.scheduler.capacity.resource-calculator禁用,这是默认设置。这是因为默认情况下,它是按内存而不是CPU计划的。
YoYo

1
更多执行程序可能会导致HDFS I / O吞吐量下降。因此,如果我根本不使用HDFS,那么在这种情况下,每个执行器可以使用5个以上的内核吗?
达山(Darshan),

我虽然在每个节点上都运行应用程序主控。按上述,这意味着只有1个Application Master可以运行作业。那是对的吗?
Roshan Fernando

15

根据Sandy Ryza的说法,当您在HDFS之上运行spark应用程序时

我注意到,HDFS客户端在处理大量并发线程时遇到了麻烦。一个粗略的猜测是,每个执行者最多可以完成五个任务,以实现完整的写入吞吐量,因此最好将每个执行者的内核数量保持在该数量以下。

因此,我认为您的第一个配置要慢于第三个配置,这是因为HDFS I / O吞吐量很差


11

我自己还没有玩这些设置,所以这只是猜测,但如果我们将此问题视为分布式系统中的正常核心和线程,那么在您的集群中,您最多可以使用12个核心(4 * 3台计算机)和24个线程(8 * 3台机器)。在前两个示例中,您为作业提供了相当数量的内核(潜在的计算空间),但是在这些内核上运行的线程(作业)的数量非常有限,以致您无法使用分配的大量处理能力因此,即使分配了更多的计算资源,该作业也会变慢。

您提到您的关注点是在改组步骤中-虽然很好地限制改组步骤中的开销,但利用群集的并行化通常更为重要。想想极端情况-零洗牌的单线程程序。


感谢您的回答。但是我怀疑线程数不是主要问题。我添加了监视屏幕截图。如图所示,1)可以使用给定的CPU能力。
zeodtr 2014年

1
@zeodtr pwilmot是正确的-您需要最少2-4个任务才能充分利用内核的潜力。这么说吧-我通常为80个核心群集至少使用1000个分区。
samthebest 2014年

@samthebest我想知道的是1)和3)之间的性能差异的原因。当我观看Spark UI时,它们在第2节中并行运行21个任务。(为什么现在不知道21是3,所以不是24),但是3)的任务运行得更快。
zeodtr 2014年

10

简短的回答:我认为tgbaggio是正确的。您在执行程序上达到HDFS吞吐量限制。

我认为这里的答案可能比这里的一些建议简单一些。

对我来说,线索是在群集网络图中。对于运行1,利用率稳定在〜50 M字节/秒。对于运行3,稳定利用率提高了一倍,约为100 M字节/秒。

该Cloudera的博客文章通过共享DzOrd,你可以看到这个重要的报价:

我注意到,HDFS客户端在处理大量并发线程时遇到了麻烦。粗略猜测是,每个执行者最多可以完成五个任务,以实现完整的写入吞吐量,因此最好将每个执行者的内核数量保持在该数量以下。

因此,让我们做一些计算,看看如果这是真的,我们期望获得什么样的性能。


运行1:19 GB,7核,3个执行程序

  • 3个执行者x 7个线程= 21个线程
  • 每个执行者具有7个内核,我们希望对HDFS的IO有限(最多5个内核)
  • 有效吞吐量〜= 3个执行程序x 5个线程= 15个线程

运行3:4 GB,2个内核,12个执行程序

  • 2个执行程序x 12个线程= 24个线程
  • 每个执行程序2个内核,因此hdfs吞吐量还可以
  • 有效吞吐量〜= 12个执行程序x 2个线程= 24个线程

如果作业是100%受并发(线程数)限制的。我们希望运行时与线程数完全成反比。

ratio_num_threads = nthread_job1 / nthread_job3 = 15/24 = 0.625
inv_ratio_runtime = 1/(duration_job1 / duration_job3) = 1/(50/31) = 31/50 = 0.62

所以 ratio_num_threads ~= inv_ratio_runtime,看来我们受网络限制。

相同的效果说明了运行1和运行2之间的区别。


运行2:19 GB,4核,3个执行程序

  • 3个执行者x 4个线程= 12个线程
  • 每个执行器具有4个内核,可以将IO转换为HDFS
  • 有效吞吐量〜= 3个执行程序x 4个线程= 12个线程

比较有效线程数和运行时:

ratio_num_threads = nthread_job2 / nthread_job1 = 12/15 = 0.8
inv_ratio_runtime = 1/(duration_job2 / duration_job1) = 1/(55/50) = 50/55 = 0.91

它不像上次比较那样完美,但是当我们丢失线程时,我们仍然看到类似的性能下降。

现在来看最后一点:为什么会出现这样的情况,尤其是在使用更多线程的情况下我们可以获得更好的性能。比CPU数量更多的线程?

并行性(我们所得到的瓜分到多个CPU数据)和并发性(我们得到什么,当我们使用多线程做单CPU的工作),在这个伟大的职位由罗布·派克提供之差的一个很好的解释:并发不是并行性

简短的解释是,如果Spark作业正在与文件系统或网络进行交互,则CPU将花费大量时间等待与这些接口的通信,而实际上并没有花费大量时间来“工作”。通过给这些CPU一次执行多个任务,他们花费的等待时间更少,工作时间更长,并且您会看到更好的性能。


1
有趣而令人信服的解释,我想知道您是否猜出了执行器有5个任务限制才能实现最大吞吐量。

因此,数字5不是我想出的:我只是注意到IO瓶颈的迹象,然后去寻找那些瓶颈可能来自何处。
turtlemonvh

8

RStudio的Sparklyr软件包页面上可用的优秀资源中:

火花定义

为Spark术语提供一些简单的定义可能会很有用:

节点:服务器

工作者节点:属于集群的服务器,可用于运行Spark作业

主节点:协调工作节点的服务器。

执行程序:节点内的一种虚拟机。一个节点可以有多个执行程序。

驱动节点:启动Spark会话的节点。通常,这将是sparklyr所在的服务器。

驱动程序(执行程序):驱动程序节点也将显示在执行程序列表中。



1

我认为前两个配置中有一个小问题。线程和核心之类的概念如下。线程的概念是,如果核心是理想的,则使用该核心来处理数据。因此,在前两种情况下无法充分利用内存。如果要对本示例进行基准测试,请选择每台计算机上具有10个以上内核的计算机。然后做基准测试。

但是不要给每个执行器5个以上的内核,否则I / O性能将受到瓶颈的影响。

因此,执行此基准测试的最佳机器可能是具有10个核心的数据节点。

数据节点机器规格:CPU:酷睿i7-4790(内核数量:10,线程数量:20)RAM:32GB(8GB x 4)HDD:8TB(2TB x 4)


0

我认为主要原因之一是本地性。您输入的文件大小为165G,该文件的相关块肯定分布在多个DataNode上,更多执行者可以避免网络复制。

尝试将执行程序数设置为等于块数,我认为可以更快。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.