Spark:创建DataFrame所需的内存是否有点等于输入数据的大小?

时间:2016-12-14 04:58:19

标签: apache-spark

我很难说我是否需要1TB的内存来加载基于1TB数据库表的Spark DataFrame。是这种情况吗?

我被告知我在another question中没有以非常火花的方式做事,因为我开始通过迭代创建DataFrames然后处理这些子集来分块数据。问题是这太慢了,因为没有足够的并行处理发生。然后根据反馈,我尝试加载一个整个表,然后使用Spark分区/分组/排序按我需要的顺序获取我需要的东西,但据我所知,它只是填满了尽可能多的内存因为我分配(在我的本地测试机器上),尽管有多达数千个分区(在我的情况下)是一个30GB的小型数据库表。

这让我很疯狂,因为我已经在过去几周内完成了大量搜索和阅读文章和文档,而且我很难找到实际访问Spark的使用示例我甚至称之为模糊的“大”数据集。特别是在涉及DataFrames并使用真实数据库作为输入时。另外得到反馈说我不应该手动分块任何数据让我觉得必须有一些神奇的事情,而不是所有数据实际上一次被选中。在这方面任何有用的资源都将非常感激。

1 个答案:

答案 0 :(得分:5)

在以下情况下,您绝对应该cache() RDD和DataFrame:

  • 在迭代循环中重用它们
  • 在单个应用程序中重复使用RDD,作业
  • 当重新生成RDD分区的前期成本很高时(即HDFS,在一组复杂的map()filter()等之后)如果Worker节点死亡,这有助于恢复过程

请记住,Spark会以LRU方式自动从Workers中驱逐RDD分区。 LRU驱逐在每个Worker上独立发生,并取决于Worker中的可用内存。

在RDD的生命周期中,RDD分区可能存在于整个群集的内存或磁盘上,具体取决于可用内存。

Spark UI上的“存储”选项卡显示在任何给定时间点,群集中存在分区(内存或磁盘)的位置。

请注意,cache()persist(StorageLevel.MEMORY_ONLY)的别名,对于大于可用群集内存的数据集而言可能并不理想。被驱逐出内存的每个RDD分区都需要从源代码(即HDFS,网络等)重建,这是昂贵的。

更好的解决方案是使用persist(StorageLevel.MEMORY_AND_DISK_ONLY),如果RDD分区从内存中逐出,它们会将RDD分区溢出到Worker的本地磁盘。在这种情况下,重建分区只需要从Worker的本地磁盘中提取相对较快的数据。

您还可以通过附加_SER来选择将数据保存为序列化字节数组,如下所示:MEMORY_SERMEMORY_AND_DISK_SER。这可以节省空间,但会产生额外的序列化/反序列化惩罚。因为我们将数据存储为序列化字节数组,所以创建的Java对象较少,因此GC压力会降低。

Spark Storage Level