Spark 为什么可以更高效

谈到 Spark,我们总是强调它比 Hadoop 更高效。为什么它可以更高效呢?是因为它优先使用内存存储?还是因为它拥有比 MapReduce 更简单高效的计算模型?

与 Hadoop 的区别

我们知道在 Hadoop 中,一个作业(Job)可以有一个或多个Task,Task 又可以分成 Map Task 和 Reduce Task。每个Task 分别在自己的进程中运行,Hadoop 中一个 Task 就是一个进程,其模型如下:
Spark 为什么可以更高效
在 Spark 中,同样有作业(Job)的概念。一个 Application 和一个 SparkContext 相关联,每个Application 可以有一个或多个 Job并行运行。每个 Job 中包含多个 stage,stage 中????️包含多个 Task,多个Task 构成 Task set,Spark 中的task 可以理解为线程,其模型如下:
Spark 为什么可以更高效
与 MapReduce 一个应用一次只能运行一个 Map 和 一个Reduce 不同,Spark 可以根据应用的复杂程度,分割成更多的 stage,这些 stage 组成一个DAG(有向无环图),spark 任务调度器根据 DAG 的依赖关系执行 stage。

执行流程

Spark 中有两个重要的进程:DriverExecutor 。Driver 构建 SparkContext ,初始化执行配置和输入数据。SparkContext 启动 DAGScheduler 构造执行的 DGA,切分成最小的执行单位。

Driver 向 Cluster Manager 请求计算资源,用于 DAG 的分布式计算。Cluster Manager 收到请求后,将 Driver 的主机地址等信息通知给集群的所有计算节点 Worker。

Worker 收到信息后,根据 Driver 的主机地址和 Driver 通信,并注册,然后根据自己的空闲资源向 Driver 通报自己可以领用的任务数。Driver 根据 DAG 开始向注册的 Worker 分配任务。你可以将这里的 Driver 类比 Yarn 中的 ApplicationMaster,都具有任务调度的能力。

Worker 收到任务后,启动 Executor 进程执行任务,Executor 拥有线程池,管理 Task 线程,其过程如下:
Spark 为什么可以更高效

RDD(弹性分布式数据集 )

通常说 Spark 基于 RDD 模型,具有良好的通用性、容错性和并行处理数据的能力。为什么这样说?

RDD 是数据集的描述,不是数据集本身。它描述的是只读的、可分区的弹性分布式数据集。RDD 使用户能显示将计算结果保存在内存中,控制数据的划分,并使用更丰富的操作集合来处理,它具有懒操作(计算延迟,action 时候才操作)、瞬时性(用时产生,用完释放)等特性。

如何保证容错?RDD 记录数据变换而不是数据本身,当部分数据丢失时,RDD 拥有足够的信息得知这部分数据如何被计算到的,可以通过这些计算来重新得到丢失的数据。这种恢复数据的方法很快,无需大量数据复制操作。

Spark 针对 RDD 提供了两类操作:transformations 和 action。transformations 采用懒策略,仅在对相关 RDD 进行action 提交时才触发计算。Spark 中常见的 transformations 和 action 操作如下图所示:
Spark 为什么可以更高效

RDD 依赖关系

谈到 RDD,我们不得不提 RDD 中的两种典型的依赖关系:宽依赖和窄依赖。我们知道每个 RDD 包含了 partition(分区)的集合,partition 是不可分割的。宽依赖指的是前一个RDD 中的 partition 被后一个 RDD 中的多个 partition 使用;窄依赖指的前一个 RDD 的每个 partition 只被后一个 RDD 的一个 partition 使用。

Spark 中 stage 的划分依据是 shuffle,每个stage 内部尽可能多的包含一组具有窄依赖关系的转换,并将它们流水线并行化。其划分逻辑如下图所示:
Spark 为什么可以更高效
每个 partition 的计算就是一个 task,RDD 的依赖关系也可以理解成 task 的执行关系。