我正在尝试找出在群集节点上配置内存的最佳方法。但是我相信,为此,我需要进一步了解一些事情,例如spark如何处理任务中的内存。
例如,假设我有3个执行程序,每个执行程序可以并行运行多达8个任务(即8个核心)。如果我有一个带有24个分区的RDD,这意味着理论上所有分区都可以并行处理。但是,如果我们在此处放大一个执行程序,则假定每个任务都可以将其分区放在内存中以对其进行操作。如果不是那么这意味着不会发生并行的8个任务,并且需要一些调度。
因此我得出结论,如果一个人寻求真正的并行性,对分区的大小有所了解会有所帮助,因为它会告诉你如何确定执行者的大小以实现真正的并行性。
Q0 - 我只想更好地理解,什么时候会发生什么 所有分区都可以放在一个执行器内的内存中?有一些 溢出在磁盘上,而其他人在内存中进行操作?火花了 为每个任务保留内存,如果检测到没有 足够,它安排任务吗?或者只是简单地跑出去 内存错误。
Q1 - 真正的并行性 执行程序还取决于执行程序可用的内存量? 换句话说,我的群集中可能有8个核心,但如果我没有 足够的内存一次加载我的数据的8个分区,然后我不会 完全平行。
作为最后一点,我已经多次看到以下声明,但发现它有点令人困惑:
“增加分区数量也有助于减少 内存不足错误,因为这意味着Spark将在一个 每个执行者的较小数据子集。“
这是如何工作的?我的意思是火花可能适用于较小的子集,但如果总分区组无法适应内存,会发生什么?
答案 0 :(得分:6)
我想先回答最后一个令你困惑的问题。 以下是另一个question:
的引用Spark不需要在内存中加载所有内容以便能够处理它。这是因为Spark会将数据划分为更小的块并分别对这些块进行操作。
事实上,默认情况下,Spark会将to split input data automatically尝试到一些最佳分区数:
Spark会根据文件的大小自动设置要在每个文件上运行的“地图”任务的数量
可以指定正在执行的操作的分区数(例如cogroup
:def cogroup[W](other: RDD[(K, W)], numPartitions: Int)
),并且在任何RDD转换后也可以执行.repartition()
。
此外,他们在文档的同一段后面说:
通常,我们建议群集中每个CPU核心有2-3个任务。
总结:
简而言之,通过划分输入和中间结果(RDD)。通常,每个小块都适合执行程序可用的内存,并且可以快速处理。
Spark能够计算caching the RDDs。默认情况下,每次重复使用RDD时,都会重新计算(不会缓存);调用.cache()
或.persist()
有助于将结果保存在内存中或磁盘上。
每个执行程序内部都有一个在执行和存储之间浮动的内存池(有关详细信息,请参阅here)。当没有足够的内存用于任务执行时,Spark首先尝试逐出某些存储缓存,然后将任务数据溢出到磁盘上。有关详细信息,请参阅这些slides。在blog post中详细描述了执行程序和存储内存之间的平衡,这也有一个很好的例子:
OutOfMemory通常不是直接因为输入数据较大而发生,而是因为分区不佳以及因此大的辅助数据结构,如减速器上的HashMap
(here文档再次建议分区多于执行程序) 。所以,不,OutOfMemory不会因为大输入而发生,但处理起来可能会非常慢(因为它必须从磁盘写入/读取)。他们还建议使用小到200毫秒(在运行时间内)的任务对于Spark来说是好的。
大纲:正确拆分数据:每个核心超过1个分区,每个任务的运行时间应> 200毫秒。默认分区是一个很好的起点,手动调整参数。
(我建议在1/8群集上使用1/8的输入数据子集来查找最佳分区数。)
简短回答:他们这样做。有关更多详细信息,请查看我上面提到的slides(从幻灯片#32开始)。
所有N个任务都获得了可用内存的第N部分,从而影响了彼此的“并行性”。如果我很好地解释你的真正的并行性的想法,那就是“充分利用CPU资源”。在这种情况下,是的,小内存池将导致磁盘上的数据溢出,并且计算成为IO绑定(而不是受CPU限制)。
我强烈建议整篇章节Tuning Spark和Spark Programming Guide。另见Alexey Grishchenko撰写的Spark Memory Management博客文章。