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