【问题标题】:where does df.cache() is storeddf.cache() 存储在哪里
【发布时间】:2020-03-10 04:43:41
【问题描述】:

我想了解以下代码存储在哪个节点(驱动程序或工作程序/执行程序)中

df.cache() //df is a large dataframe (200GB)

并且哪个性能更好:使用sqlcachetable或cache()。我的理解是其中一个是懒惰的,另一个是渴望的。

【问题讨论】:

    标签: apache-spark apache-spark-sql


    【解决方案1】:

    df.cache() 调用persist() 方法,该方法在存储级别上存储为MEMORY_AND_DISK,但您可以更改存储级别

    persist() 方法调用 sparkSession.sharedState.cacheManager.cacheQuery() 当您看到cacheTable 的代码时,它也会调用相同的代码 sparkSession.sharedState.cacheManager.cacheQuery()

    这意味着两者相同并且是惰性评估(仅在执行操作时评估),除了persist方法可以存储为提供的存储级别,这些是可用的存储级别

    • 无
    • DISK_ONLY
    • DISK_ONLY_2
    • MEMORY_ONLY
    • MEMORY_ONLY_2
    • MEMORY_ONLY_SER
    • MEMORY_ONLY_SER_2
    • MEMORY_AND_DISK
    • MEMORY_AND_DISK_2
    • MEMORY_AND_DISK_SER
    • MEMORY_AND_DISK_SER_2
    • OFF_HEAP

    也可以使用不延迟求值的SQLCACHE TABLE,将整个表存储在内存中,这也可能导致OOM

    总结:cache()、persist()、cacheTable() 被懒惰地评估,需要执行操作才能工作,而SQL CACHE TABLE 是一个渴望

    在这里查看details!

    您可以根据自己的要求选择!

    希望这会有所帮助!

    【讨论】:

    • 有点不正确,因为对于数据框 cache 和默认 persist 是 MEMORY_AND_DISK
    • @Shankar Koirala :当我说 df.cache() 或 persist() 时,我的问题更多是关于数据存储在哪里?当我说它在单个工作节点或驱动程序节点上的内存中或跨节点分布等时。我确实知道有多个存储级别
    • @philantrovert :能否请您提供源文档,默认情况下,persist() 是 MEMORY_AND_DISK,在这种情况下还有一个问题,当集群出现故障或应用程序重新启动时,磁盘中的数据会怎样?会被抹去吗?
    • 你去吧:github.com/apache/spark/blob/master/sql/core/src/main/scala/org/… 如果集群出现故障,你也会失去对数据的跟踪。
    【解决方案2】:

    只需加上我的 25 美分。 SparkDF.cache() 会将数据加载到执行程序内存中。 它不会加载到驱动程序内存中。这是我们想要的。 这是我刚刚运行的 df.cache().count() 后 50% 的数据负载的快照。

    Cache() 保存在内存和磁盘中,由 koiralo 描述,并且也是惰性求值的。

    Cachedtable() 存储在磁盘上,因此对节点故障具有弹性。

    信用:https://forums.databricks.com/answers/63/view.html

    【讨论】:

      【解决方案3】:

      cache(或 persist)方法将 DataFrame 标记为缓存在内存(或磁盘,如有必要,如另一个答案所述)中,但这仅在对 DataFrame 执行操作时发生,并且仅以一种懒惰的方式,即如果您最终只读取 100 行,则只有这 100 行被缓存。创建一个临时表并使用cacheTable 是急切的,因为它会立即缓存整个表。哪个性能更好取决于您的情况。我对普通 DataFrame cache 所做的一件事是立即调用 .count(),强制缓存 DataFrame,并避免注册临时表等。

      【讨论】:

        【解决方案4】:

        火花记忆。这是由 Apache Spark 管理的内存池。它的大小可以计算为(“Java Heap” – “Reserved Memory”) * spark.memory.fraction, and with Spark 1.6.0 defaults it gives us (“Java Heap” – 300MB) * 0.75. 例如,对于 4GB 堆,这个池的大小为 2847MB。整个池分为 2 个区域——存储内存和执行内存,它们之间的边界由 spark.memory.storageFraction 参数设置,默认为 0.5。这种新的内存管理方案的优点是这个边界不是静态的,在内存压力的情况下边界会被移动,即一个区域会通过从另一个区域借用空间来增长。稍后我将讨论“移动”此边界,现在让我们关注如何使用此内存:

        1. Storage Memory. 此池用于存储 Apache Spark 缓存数据和临时空间序列化数据“展开”。此外,所有“广播”变量都作为缓存块存储在那里。如果你好奇,这里是展开代码。正如您所看到的,它不需要足够的内存来提供展开的块 - 如果没有足够的内存来容纳整个展开的分区,如果所需的持久性级别允许,它将直接将其放入驱动器。从“广播”开始,所有广播变量都以 MEMORY_AND_DISK 持久性级别存储在缓存中。

        2. Execution Memory. 此池用于存储 Spark 任务执行期间所需的对象.例如,它用于在内存中存储 Map 端的 shuffle 中间缓冲区,也用于存储哈希表以进行哈希聚合步骤。如果没有足够的可用内存,该池还支持溢出到磁盘上,但该池中的块不能被其他线程(任务)强行驱逐。
        好的,现在让我们关注存储内存和执行内存之间的移动边界。由于执行内存的性质,您不能从该池中强制驱逐块,因为这是用于中间计算的数据,如果找不到它引用的块,则需要此内存的进程将简单地失败。但存储内存并非如此——它只是存储在 RAM 中的块缓存,如果我们从那里驱逐块,我们可以更新块元数据,反映该块被驱逐到 HDD(或简单地删除)的事实,并尝试访问此块 Spark 将从 HDD 读取它(或重新计算以防您的持久性级别不允许溢出到 HDD)。

        因此,我们可以从存储内存中强制驱逐该块,但不能从执行内存中这样做。 Execution Memory pool 什么时候可以从 Storage Memory 借一些空间?它发生在以下任一情况下:

        存储内存池中有可用空间,即缓存块不会使用那里的所有可用内存。然后它只是减少了存储内存池的大小,增加了执行内存池。
        存储内存池大小超过了初始存储内存区域大小,并且已使用所有这些空间。这种情况会导致从存储内存池中强制驱逐块,除非它达到其初始大小。
        反过来,只有当执行内存池中有一些空闲空间可用时,存储内存池才能从执行内存池中借用一些空间。

        您可能还记得,初始存储内存区域大小计算为“Spark Memory” * spark.memory.storageFraction = (“Java Heap” – “Reserved Memory”) * spark.memory.fraction * spark.memory.storageFraction。使用默认值,这等于(“Java Heap” – 300MB) * 0.75 * 0.5 = (“Java Heap” – 300MB) * 0.375. For 4GB heap this would result in 1423.5MB of RAM in initial Storage Memory region。

        参考-https://0x0fff.com/spark-memory-management/

        【讨论】:

        • 嗨 Kishore,感谢您的解释。我有一个基本问题。广播变量存储在工作节点中的位置。我相信缓存将存储在 spark.memory.storageFraction 部分。在此先感谢...
        猜你喜欢
        • 1970-01-01
        • 2011-08-14
        • 2023-04-03
        • 2018-04-29
        • 2010-11-02
        • 2016-10-22
        • 2021-07-30
        • 2012-05-23
        • 2011-06-26
        相关资源
        最近更新 更多