Apache Spark是在同一时间读取和处理,还是首先在内存中读取整个文件然后开始转换?

Yoh*_*oth 5 hadoop apache-spark

我很好奇,如果Spark首先将整个文件读入内存,然后才开始处理它,意味着应用转换和操作,或者它读取文件的第一个块 - 对其应用转换,读取第二个块等等.

对于同样的问题,Spark在Hadoop中有什么区别吗?我读到Spark大多数时候将整个文件保存在内存中,而Hadoop则没有.但是,当我们第一次阅读它并映射键时,第一步是怎么回事.

谢谢

Arm*_*aun 2

我认为一个公平的描述应该是这样的:

Hadoop(或更准确地说 MapReduce)和 Spark 都使用相同的底层文件系统 HDFS。

在映射阶段,两者都会读取所有数据并将映射结果实际写入磁盘,以便可以通过 Shuffle 逻辑在节点之间排序和分发。事实上,除了将数据溢出到磁盘以便 Shuffle 完成其工作之外,它们都尝试缓存刚刚映射到内存中的数据。但这里的区别在于,Spark 在此过程中效率更高,它尝试将为特定计算选择的节点与已缓存在某个节点上的数据进行最佳对齐。由于 Spark 还执行惰性评估功能,因此 Spark 的内存使用与 Hadoop 非常不同,因为它同时规划计算和缓存。

在字数统计作业的步骤中,Hadoop 执行以下操作:

  1. 将所有单词映射到1.
  2. 将所有这些映射对 (word, 1) 写入 HDFS 中的单个文件(单个文件仍然可以跨越分布式 HDFS 上的多个节点)(这是 shuffle 阶段)
  3. 对共享文件中 (word, 1) 的行进行排序(这是排序阶段)
  4. 让缩减器从该共享文件中读取部分(分区),该文件现在包含所有已排序的单词,并对每个单词的所有这些进行求和1

另一方面,Spark 则相反:

  1. 它认为,就像在 Hadoop 中一样,通过单独的Reducer 运行来汇总所有这些单词可能是最有效的,因此它根据一些因素决定将作业拆分为 x 个部分,然后将它们合并到最终结果中。
  2. 因此它知道必须对单词进行排序,这将需要在给定时间至少将部分单词存储在内存中。
  3. 之后,它评估这样的排序列表将需要映射到(单词,1)对的所有单词来开始计算。
  4. 它通过步骤 3 比 2 比 1 进行。

现在与 Hadoop 相关的技巧是,它在步骤 3 中知道在步骤 2 中需要哪些内存缓存项,并且在步骤 2 中它已经知道在最后的步骤 1 中如何需要这些部分(主要是 KV 对)。这使得 Spark 能够非常有效地计划作业的执行,但缓存它知道在作业的后期阶段将需要的数据。Hadoop 从开始(映射)到结束都在没有明确地展望后续阶段的情况下工作,根本无法如此有效地使用内存,因此不会浪费资源将 Spark 会保留的大块保留在内存中。与 Spark 不同的是,它只是不知道下一步是否需要 Map 阶段中的所有对。

事实上,Spark 似乎将整个数据集保留在内存中,因此这并不是 Spark 主动执行的操作,而是 Spark 能够计划作业执行的方式的结果。另一方面,Spark 在不同类型的作业中实际上可能能够保留更少的内存。在我看来,计算不同单词的数量是一个很好的例子。在这里,Spark 会提前计划,并在映射过程中遇到重复词时立即从缓存/内存中删除重复词,而在 Hadoop 中,它会继续进行并在打乱重复词时浪费内存(我承认有一百万种方法可以也可以让 Hadoop 做到这一点,但它不是开箱即用的,也有一些方法以不幸的方式编写 Spark 作业来破坏这些优化,但在这里欺骗 Spark 并不那么容易:))。

希望这有助于理解内存使用只是 Spark 工作方式的自然结果,而不是主动针对的东西,也不是 Spark 严格要求的东西。当内存出现问题时,它还完全能够在执行步骤之间反复将数据溢出回磁盘。

为了更深入地了解这一点,我建议从这里了解 Spark 中的 DAG 调度程序,看看这实际上是如何在代码中完成的。您会发现它始终遵循这样的模式:先确定哪些数据在哪里以及哪些数据将被缓存,然后再确定要在哪里计算哪些数据。