我试图了解在YARN上运行Spark作业时内核数量和执行程序数量之间的关系。
测试环境如下:
网络:1Gb
Spark版本:1.0.0
Hadoop版本:2.4.0(Hortonworks HDP 2.1)
Spark工作流程:sc.textFile - >过滤器 - >地图 - >过滤器 - > mapToPair - > reduceByKey - >地图 - > saveAsTextFile
输入数据
输出
该作业使用以下配置运行:
--master yarn-client --executor-memory 19G --executor-cores 7 --num-executors 3
(每个数据节点的执行者,使用核心)
--master yarn-client --executor-memory 19G --executor-cores 4 --num-executors 3
(核心数量减少)
--master yarn-client --executor-memory 4G --executor-cores 2 --num-executors 12
(少核心,更多执行者)
经过的时间:
50分15秒
55分钟48秒
31分23秒
令我惊讶的是,(3)更快 我认为(1)会更快,因为改组时执行者间的沟通会更少 虽然(1)的核心数少于(3),但核心数不是关键因素,因为2)表现良好。
(在pwilmot回答之后添加了以下内容。)
有关信息,性能监视器屏幕截图如下:
图表大致分为两部分:
如图所示,(1)可以使用尽可能多的CPU功率。所以,它可能不是线程数量的问题。
如何解释这个结果?
答案 0 :(得分:48)
为了让所有这些更加具体,这里有一个配置Spark应用程序以使用尽可能多的集群的工作示例 可能:想象一下,每个运行NodeManagers的六个节点的集群 配备 16核和64GB内存。 NodeManager的容量, yarn.nodemanager.resource.memory-mb和 yarn.nodemanager.resource.cpu-vcores,应该设置为63 * 1024 = 64512(兆字节)和15。我们避免分配100% YARN容器的资源,因为节点需要一些 运行操作系统和Hadoop守护进程的资源。在这种情况下,我们留下一个 千兆字节和这些系统进程的核心。 Cloudera Manager帮助 通过考虑这些并配置这些YARN属性 自动。
可能的第一个冲动是使用 - num-executors 6 --executor-cores 15 --execeror-memory 63G 。但是,这是错误的方法,因为:
63GB +执行程序内存开销不适合63GB容量 NodeManagers。应用程序主机将在一个核心上占用核心 节点,意味着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博客的一篇文章中给出的 http://blog.cloudera.com/blog/2015/03/how-to-tune-your-apache-spark-jobs-part-2/
答案 1 :(得分:14)
我注意到HDFS客户端遇到大量并发问题 线程。一个粗略的猜测是,每个执行者最多五个任务 实现完全写入吞吐量,所以保持数量是很好的 每个执行者的核心数低于该数字。
所以我认为你的第一个配置比第三个慢,因为HDFS I / O吞吐量不好
答案 2 :(得分:11)
我自己还没有使用过这些设置,所以这只是推测,但如果我们将此问题视为分布式系统中的普通内核和线程,那么在群集中最多可以使用12个内核(4 * 3)机器)和24个线程(8 * 3机器)。在前两个示例中,您为工作提供了相当数量的核心(可能的计算空间),但在这些核心上运行的线程(作业)数量非常有限,以至于您无法使用大部分处理即使分配了更多的计算资源,分配的功率也因此作业速度较慢。
你提到你的问题是在洗牌步骤中 - 尽管限制洗牌步骤的开销是很好的,但通常更重要的是利用集群的并行化。考虑一下极端情况 - 单线程程序,零洗牌。
答案 3 :(得分:2)
来自RStudio's Sparklyr package page的优秀资源:
SPARK定义:
提供一些简单的定义可能很有用 对于Spark命名法:
节点:服务器
工作线程:作为群集一部分且可用的服务器 运行Spark作业
主节点:协调工作节点的服务器。
执行程序:节点内的一种虚拟机。一个节点可以有 多个执行人员。
驱动程序节点:启动Spark会话的节点。通常情况下, 这将是sparklyr所在的服务器。
驱动程序(执行程序):驱动程序节点也将显示在执行程序中 列表。
答案 4 :(得分:2)
简短的答案:我认为tgbaggio是正确的。您对执行程序达到了HDFS吞吐量限制。
我认为这里的答案可能比这里的一些建议更简单。
对我来说,线索在群集网络图中。对于运行1,利用率稳定在〜50 M字节/秒。对于运行3,稳定利用率提高了一倍,约为100 M字节/秒。
在the cloudera blog post共享的DzOrd中,您可以看到以下重要报价:
我注意到HDFS客户端在处理大量并发线程时遇到了麻烦。一个粗略的猜测是,每个执行者最多可以完成五个任务,以实现完整的写入吞吐量,因此最好将每个执行者的内核数量保持在该数量以下。
因此,让我们做一些计算,看看如果这是真的,我们会期望什么性能。
如果作业是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之间的区别。
比较有效线程数和运行时:
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数量更多的线程?
Rob在这篇很棒的文章中很好地解释了并行性(我们将数据划分到多个CPU上获得的东西)和并发性(当我们使用多个线程在单个CPU上工作时得到的东西)之间的区别。派克:Concurrency is not parallelism。
简短的解释是,如果Spark作业正在与文件系统或网络进行交互,则CPU将花费大量时间等待与这些接口的通信,而实际上并没有花费大量时间来“工作”。通过一次为这些CPU提供多个任务来工作,他们将花费更少的等待时间和更多的时间来工作,并且您会看到更好的性能。
答案 5 :(得分:0)
我认为其中一个主要原因是地方性。您的输入文件大小为165G,文件的相关块肯定分布在多个DataNode上,更多的执行程序可以避免网络拷贝。
尝试设置executor num equal blocks count,我认为可以更快。
答案 6 :(得分:0)
Spark动态分配提供了灵活性并动态分配资源。在这个数量的最小和最大执行者可以给出。此外,还可以给出在应用程序启动时必须启动的执行程序的数量。
请阅读以下内容:
http://spark.apache.org/docs/latest/configuration.html#dynamic-allocation
答案 7 :(得分:0)
我认为前两种配置存在一个小问题。线程和核心的概念如下。线程的概念是,如果核心是理想的,那么使用该核心来处理数据。因此在前两种情况下没有充分利用内存。如果您想在此示例中进行基准测试,请选择每台计算机上具有 10核的计算机。然后做基准测试。
但是,如果每个执行程序不超过5个核心,那么i / o性能将会出现瓶颈。
因此,执行此基准测试的最佳机器可能是具有10个核心的数据节点。
数据节点机规格: CPU:Core i7-4790(核心数:10,线程数:20) 内存:32GB(8GB x 4) 硬盘:8TB(2TB x 4)