为什么spark.memory.fraction的默认值这么低?

Koe*_*dlt 6 apache-spark

Spark配置文档中,我们了解了以下有关spark.memory.fraction配置参数的信息:

用于执行和存储的(堆空间 - 300MB)的一部分。该值越低,溢出和缓存数据驱逐发生的频率就越高。此配置的目的是为内部元数据、用户数据结构以及稀疏、异常大的记录的情况下的不精确大小估计留出内存。建议将此值保留为默认值。

在撰写此问题时,此配置参数的默认值为 0.6。这意味着,对于具有 32GB 堆空间和默认配置的执行器,我们有:

  • 300MB保留空间(行上的硬编码值)
  • (32GB - 300MB) * 0.6 = 19481MB用于执行+存储的共享内存
  • (32GB - 300MB) * 0.4 = 12987MB用户内存

这个“用户内存”(根据文档用于以下用途:

其余空间 (40%) 保留用于用户数据结构、Spark 中的内部元数据,以及在稀疏和异常大的记录情况下防止 OOM 错误。

在具有 32GB 堆空间的执行器上,我们为此分配 12.7GB 内存,这感觉相当大!

这些用户数据结构/内部元数据/防止 OOM 错误真的需要那么多空间吗?是否有一些引人注目的用户内存使用示例可以说明如此大的用户内存区域的需求?

M_S*_*M_S 6

我做了一些研究,我认为它的 0.6 不是为了确保用户内存有足够的内存,而是为了确保执行+存储可以适合 jvm 的旧代区域

\n

在这里我发现了一些有趣的事情: Spark adjustment

\n
\n

终身代大小由 JVM\xe2\x80\x99s NewRatio\n参数控制,默认为 2,这意味着终身代是新生代(堆的其余部分)大小的 2 倍。因此,默认情况下,终身代占据堆的 2/3 或大约 0.66。Spark.memory.fraction 的值为 0.6 可以在老一代中保留存储和\n执行内存,并留有空闲空间。如果park.memory.fraction 增加到0.8,那么NewRatio 可能必须增加到6 或更多。

\n
\n

因此,默认情况下,在 OpenJvm 中,该比率设置为 2,因此老一代有 0,66%,他们选择使用 0,6 来获得较小的余量

\n

我发现在版本 1.6 中这被更改为 0,75 并且它导致了一些问题,这里是Jira 票证

\n

在描述中,您将找到示例代码,该代码将记录添加到缓存只是为了使用为执行+存储保留的整个内存。将存储+执行设置为比旧一代更高的量时,gc 的开销确实很高,并且在旧版本上执行的代码(此设置等于 0.6)快了 6 倍(40-50 秒 vs 6 分钟)

\n

经过讨论,社区决定在 Spark 2.0 中将其回滚到 0.6,这是经过更改的PR

\n

我认为如果你想提高一点性能,你可以尝试将其更改为 0.66,但如果你想有更多的内存用于执行+存储,你还需要调整你的 jvm 并更改旧/新比率,否则你可能会面临性能问题

\n