通常我们认为 Spark 引擎是基于内存进行计算,无论如何,速度都是比 MapReduce 快,因为 MapReduce 需要频繁 Shuffle 。在 Spark 的官网早期介绍中,也有过一张 Spark 比 Hadoop 计算速度快100倍的宣传,虽然它似乎违反了我们的广告法。
本文不讨论技术源码,从内存计算、数据共享、任务调度优化多种角度,总结 Spark 快的真因。
MapReduce 在 Shuffle 阶段,数据要经过环形缓冲区进行溢写,需要按键进行排序,以便相同键的数据可以被发送到同一个 Reducer。这可能涉及大量的数据传输,对网络和磁盘 I/O 造成负担。
Spark 计算比 MapReduce 快的根本原因在于 DAG(有向无环图) 计算模型。一般而言,DAG 相比 MapReduce 在大多数情况下可以减少 shuffle 次数。
Spark 的 DAGScheduler 相当于一个改进版的 MapReduce,如果计算不涉及与其他节点进行数据交换,Spark可以在内存中一次性完成这些操作,也就是中间结果无须落盘,减少了磁盘IO的操作,只在最后进行落盘。但是,如果计算过程中涉及数据交换,Spark 也是会把 shuffle 的数据写磁盘的!
在 MapReduce 中,任务(Mapper 和 Reducer)是进程级别的,每个任务通常运行在单独的进程中。每个 Mapper 或 Reducer 任务的执行过程中可能涉及多个线程来处理输入数据、执行计算和进行 I/O 操作。
在 Spark 中,任务是线程级别的,由执行器(Executor)中的线程池处理。每个 Executor 可以运行多个任务,每个任务由一个或多个线程处理,共享 Executor 内的内存。Spark 的任务调度和执行都是在 Executor 内部进行,Spark 管理着任务的分发、调度、失败恢复以及数据的本地性优化。
因此 Spark 的任务创建开销相对较小,使得任务可以更快地启动和执行。而MapReduce 框架中创建和销毁进程的开销较大。
Spark 提供了持久化缓存机制,通过将需要复用的数据存储在内存中,可以显著提高 Spark 应用程序的速度。这种机制可以避免重复计算和磁盘读取,从而加快数据访问和处理速度,这也正是因为线程中资源共享的特点而决定的。
而 MapReduce 每个阶段之间都需要将数据写入分布式文件系统,这会造成数据的多次复制和移动。
Spark 使用更高效的数据序列化格式,例如 Parquet、Avro 等,从而减少数据在网络上的传输和存储开销。MapReduce 默认使用的是文本格式,传输和解析开销较大。
最后,Spark 一定比 MapReduce 快100倍吗? 我们是否可以测试一种情况,使程序在 Spark 和 MapReduce 中都只走一次 Shuffle ,进行一次磁盘的IO,此时两种计算引擎谁更有优势?