如何调整Spark执行程序编号,内核和执行程序内存?


84

您从哪里开始调整上述参数。我们是从执行者的内存开始并获得执行者的数量,还是从内核开始并获得执行者编号。我点击了链接。但是有一个高水平的想法,但仍然不确定如何或在何处开始并得出最终结论。

Answers:


206

以下答案涵盖了标题中提到的3个主要方面-执行程序数,执行程序内存和内核数。可能有其他参数,例如驱动程序内存,以及我在此回答中尚未解决的其他参数,但希望在不久的将来添加。

情况1硬件-6个节点,每个节点16个内核,64 GB RAM

每个执行程序都是一个JVM实例。因此,我们可以在单个Node中拥有多个执行程序

OS和Hadoop守护程序需要前1个核心和1 GB,因此可用的是15个核心,每个节点63 GB RAM

从如何选择核数开始

Number of cores = Concurrent tasks as executor can run 

So we might think, more concurrent tasks for each executor will give better performance. But research shows that
any application with more than 5 concurrent tasks, would lead to bad show. So stick this to 5.

This number came from the ability of executor and not from how many cores a system has. So the number 5 stays same
even if you have double(32) cores in the CPU.

执行者人数:

Coming back to next step, with 5 as cores per executor, and 15 as total available cores in one Node(CPU) - we come to 
3 executors per node.

So with 6 nodes, and 3 executors per node - we get 18 executors. Out of 18 we need 1 executor (java process) for AM in YARN we get 17 executors

This 17 is the number we give to spark using --num-executors while running from spark-submit shell command

每个执行者的记忆:

From above step, we have 3 executors  per node. And available RAM is 63 GB

So memory for each executor is 63/3 = 21GB. 

However small overhead memory is also needed to determine the full memory request to YARN for each executor.
Formula for that over head is max(384, .07 * spark.executor.memory)

Calculating that overhead - .07 * 21 (Here 21 is calculated as above 63/3)
                            = 1.47

Since 1.47 GB > 384 MB, the over head is 1.47.
Take the above from each 21 above => 21 - 1.47 ~ 19 GB

So executor memory - 19 GB

最终数字-执行程序-17,核心5,执行程序内存-19 GB


情况2硬件:相同的6节点,32核,64 GB

5表示相同的并发性

每个节点的执行者数量= 32/5〜6

因此,总执行者= 6 * 6节点=36。那么对于AM = 35,最终数目是36-1

执行程序内存为:每个节点6个执行程序。63/6〜10。开销为.07 * 10 = 700 MB。因此,将总开销舍入到1GB,我们得到10-1 = 9 GB

最终编号-执行程序-35,核心5,执行程序内存-9 GB


情况3

以上方案从接受固定的内核数量开始,然后转移到执行程序和内存的数量。

现在,对于第一种情况,如果我们认为不需要19 GB,而仅10 GB就足够了,那么以下是数字:

每个节点的5个执行程序核心数= 3

在此阶段,根据我们的第一个计算,将得出21,然后是19。但是由于我们认为10没问题(假设开销很小),因此我们无法将每个节点的执行程序数切换为6(例如63/10)。如果每个节点有6个执行程序和5个核心,那么当我们只有16个核心时,则可以减少到每个节点30个核心。因此,我们还需要为每个执行程序更改核心数。

所以再次计算

魔术数字5等于3(小于或等于5的任何数字)。因此,具有3个核心和15个可用核心-每个节点可获得5个执行程序。因此(5 * 6 -1)= 29个执行者

因此内存为63/5〜12。开销为12 * .07 = .84因此执行程序内存为12-1 GB = 11 GB

最终编号为29个执行程序,3个内核,执行程序内存为11 GB


动态分配:

注意:如果启用了动态分配,则执行者数量的上限。因此,这表明spark应用程序可以在需要时吞噬所有资源。因此,在您正在运行其他应用程序且它们也需要内核才能运行任务的群集中,请确保您在群集级别执行此操作。我的意思是您可以根据用户访问权限为YARN分配特定数量的内核。因此,您可以创建spark_user可能是,然后为该用户指定核心(最小/最大)。这些限制是在spark和在YARN上运行的其他应用程序之间共享的。

spark.dynamicAllocation.enabled-设置为true时-无需提及执行程序。原因如下:

我们在提交火花时给出的静态参数编号是整个工作期间的。但是,如果考虑到动态分配,则会有不同的阶段,例如

从什么开始:

开始的执行者的初始数量(spark.dynamicAllocation.initialExecutors

多少 :

然后根据负载(待处理的任务)请求多少。这最终将是我们以静态方式提交火花时提供的数字。因此,一旦设置了初始执行程序编号,便转到最小(spark.dynamicAllocation.minExecutors)和最大(spark.dynamicAllocation.maxExecutors)数字。

何时提出或给予:

我们什么时候请求新的执行者(spark.dynamicAllocation.schedulerBacklogTimeout)-在这么长的时间内有待处理的任务。所以要求。每轮请求的执行者数量与前一轮成倍增加。例如,一个应用程序将在第一轮中添加1个执行器,然后在随后的轮中添加2、4、8,依此类推。在特定的点,上面的最大值变成图片

我们什么时候放弃执行程序(spark.dynamicAllocation.executorIdleTimeout)-

如果我错过任何事情,请纠正我。以上是我根据有问题的博客和一些在线资源得出的理解。谢谢。

参考文献:


2
我读到某处,在独立模式下每个节点只有一个执行程序,对此有什么想法吗?我看不到您的答案涵盖了它。
jangorecki

2
在独立群集中,默认情况下,每个工作人员只有一名执行者。我们需要使用spark.executor.cores,并且一个工作人员具有足够的核心以获取多个执行者。
Ramzy

我发现我的工作人员无需设置即可使用全部32个内核spark.executor.cores,因此默认情况下它可以使用所有可用的内核。
jangorecki

是的,正如他们所说,内核的默认值是无限的。因此,除非您指定,否则spark可以使用所有可用的内核。
Ramzy

2
@Ramzy我想应该指出的是,即使使用动态分配,您仍然应该指定spark.executor.cores来确定Spark将要分配的每个执行器的大小。否则,每当Spark打算为您的应用程序分配新的执行程序时,即使您仅需要五个核,它也将分配整个节点(如果可用)。
Dan Markhasin

6

另外,这取决于您的用例,一个重要的配置参数是:

spark.memory.fraction(来自http://spark.apache.org/docs/latest/configuration.html#memory-management的部分(用于执行和存储的(堆空间-300MB))。

如果您不使用缓存/持久性,请将其设置为0.1,以便您拥有程序的所有内存。

如果使用缓存/持久性,则可以检查以下对象占用的内存:

sc.getExecutorMemoryStatus.map(a => (a._2._1 - a._2._2)/(1024.0*1024*1024)).sum

您是从HDFS还是从HTTP读取数据?

同样,调整取决于您的用例。


您知道使用pyspark时map命令的样子吗?我使用sc._jsc.sc()。getExecutorMemoryStatus()来获取执行者状态,但返回的内容无法执行任何操作……
Thomas

1
抱歉@Thomas Decaux,但您的意思是设置spark.memory.storageFraction=0.1吗?因为据我所知spark.memory.fraction决定所使用的内存量Spark为双方执行和存储(你已经提到),只有spark.memory.storageFraction内存(可用存储+执行)是由免疫高速缓存收回。请参阅此链接
y2k-shubham

@Thomas如果在我的应用程序中我只有persist(StorageLevel.DISK_ONLY),那么此选项也适用吗?它仅影响内存部分,但不影响任何磁盘溢出吗?
jk1
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.