当缓存的MEMORY_ONLY持久性数据不适合内存时,spark如何处理内存不足错误?

问题描述

我是新手,我无法找到明确的答案:当缓存的数据不适合内存时会发生什么?

我发现很多地方,如果RDD不能容纳在内存中,则某些分区将不会被缓存,并且每次需要时都会进行实时重新计算。

例如:让我们说创建了500个分区,并说没有缓存200个分区,那么我们不得不再次通过重新评估RDD重新计算剩下的200个分区。

如果是这种情况,那么就永远不会发生OOM错误,而是会发生。原因是什么?

高度赞赏详细的解释。在此先感谢

解决方法

有多种方法可以将数据持久保存在Spark中。

1)坚持(MEMORY_ONLY)

当您使用MEMORY_ONLY持久化数据帧时,它将作为反序列化的Java对象缓存在spark.cached.memory节中。如果RDD不能容纳在内存中,则某些分区将不会被缓存,并且每次需要时都会即时重新计算。这是默认级别,当RDD太大而无法容纳在内存中时(有时也会在重新计算之后出现),有时会导致OOM。

回答您的问题

如果是这种情况,那么就永远不会发生OOM错误,但确实会发生。原因是什么? 即使重新计算后,也需要将那些rdd放入内存中。如果没有可用空间,则GC将尝试清理某些部分并尝试对其进行分配。如果未成功,则它将失败并显示OOM


2)坚持(MEMORY_AND_DISK)

当您使用MEMORY_AND_DISK持久化数据帧时,如果堆中没有可用的内存,则它将作为反序列化Java对象缓存在spark.cached.memory节中,然后将其溢出到磁盘中。为了解决内存问题,它将溢出部分数据或将完整数据泄漏到磁盘。 (注意:请确保节点中有足够的磁盘空间,否则会弹出无磁盘空间错误)


3)坚持(MEMORY_ONLY_SER) 当您使用MEMORY_ONLY_SER持久保存数据帧时,它将作为序列化Java对象(每个分区一个字节数组)缓存在spark.cached.memory节中。这通常比MEMORY_ONLY更节省空间,但是这是一个CPU密集型任务,因为涉及压缩(一般建议此处使用Kyro进行序列化),但这仍然面临类似于MEMORY_ONLY的OOM问题。


4)坚持(MEMORY_AND_DISK_SER) 它类似于MEMORY_ONLY_SER,但区别是没有堆空间可用时,它将RDD数组溢出到磁盘上,就像(MEMORY_AND_DISK)一样。当您对磁盘空间有严格限制时,我们可以使用此选项减少IO流量。


5)坚持(DISK_ONLY) 在这种情况下,不使用堆内存.RDD保留在磁盘上。确保有足够的磁盘空间,此选项将产生大量的IO开销。当您有重复使用的数据框时,请勿使用此功能。


6)坚持(MEMORY_ONLY_2或MEMORY_AND_DISK_2) 这些类似于上面提到的MEMORY_ONLY和MEMORY_AND_DISK。唯一的不同是这些选项只是为了安全起见在两个群集节点上复制每个分区。在使用竞价型实例时请使用这些选项。


7)坚持(OFF_HEAP) 堆外内存通常包含线程堆栈,Spark容器应用程序代码,网络IO缓冲区和其他OS应用程序缓冲区。即使您可以使用上述选项从RAM中使用这部分内存来缓存RDD。