大数据技术原理与应用 - (10). Spark
【第三篇】 - 大数据处理与分析, 《大数据技术原理与应用, 林子雨》
本篇介绍大数据处理与分析的相关技术,包括
- 第7章 - MapReduce
- 第8章 - Hive - 基于 Hadoop 的数据仓库
- 第9章 - Hadoop 的优化与发展
- 第10章 - Spark
- 第11章 - 流计算
- 第12章 - 图计算
Spark 最初诞生于伯克利大学的 APM 实验室,是一个可应用于大规模数据处理的快速、通用引擎,如今是 Apache 软件基金会下的顶级开源项目之一。Spark 在借鉴Hadoop MapReduce 优点的同时,很好地解决了 MapReduce 所面临的问题。
Spark 概述
Spark 简介
Spark 最初诞生于 University of California, Berkeley 的 APM 实验室,是一个可应用于大规模数据处理的快速、通用引擎,如今是 Apache 软件基金会下的顶级开源项目之一。
Spark 特点:
- 运行速度快:使用 DAG 执行引擎以支持循环数据流与内存计算。
- 容易使用:支持使用 Scala、Java、Python 和 R 语言进行编程,可以通过 Spark Shell 进行交互式编程。
- 通用性:Spark 提供了完整而强大的技术栈,包括 SQL 查询、流式计算、机器学习和图算法组件。
- 运行模式多样:可运行于独立的集群模式中,可运行于 Hadoop 中,也可运行于 Amazon EC2 等云环境中,并且可以访问 HDFS、Cassandra、HBase、Hive 等多种数据源。
Spark 和 Hadoop 对比
Hadoop 缺点:
- 表达能力有限。计算必须要转化成 Map 和 Reduce 两个操作,但这并不适合所有情况。
- 磁盘 IO 开销大。每次执行和结束都需分别从磁盘中读取和写入数据或中间结果。
- 延迟高。
- 任务之间的衔接涉及 IO 开销
- 在前一个任务执行完成之前,其他任务就无法开始,难以胜任复杂、多阶段的计算任务
Spark 在借鉴Hadoop MapReduce 优点的同时,很好地解决了 Hadoop MapReduce 所面临的问题。相较于 Hadoop,Spark 的优点有:
- Spark 的计算模式也属于 MapReduce,但不局限于 Map 和 Reduce 操作,还提供了多种数据集操作类型,编程模型比Hadoop MapReduce更灵活。
- 提供 内存计算,可将中间结果放到内存中,带来了更高的迭代运算效率。
- 基于 DAG 的任务调度执行机制,优于 MapReduce 的迭代执行机制。
- 使用 Hadoop 进行迭代计算非常耗资源,因为频繁从磁盘中读写数据。
- Spark 将数据载入内存后,之后的迭代计算都可以直接使用内存中的中间结果作运算,避免了从磁盘中频繁读取数据。
Spark 生态系统
在实际应用中,大数据处理主要包括一下三大类型 (应用场景)。
- 复杂的批量数据处理: 时间跨度通常在数十分钟到数小时之间。(Hadoop)
- 基于历史数据的交互式查询: 时间跨度通常在数十秒到几分钟之间。(Impala)
- 基于实时数据流的数据处理: 时间跨度通常在数百毫秒到数秒之间。(Storm)
对于互联网公司而言,通常会同时存在以上三种场景,就同时需要部署三种不同的软件,多软件难免带来一些问题。
- 不同场景之间输入输出数据无法做到无缝共享,通常需要进行数据格式的转换。
- 不同软件需要不同的开发和维护团队,带来了较高的使用成本。
- 比较难以对同一个集群中的各个系统进行统一的资源协调和分配。
Spark 生态系统已经成为伯克利数据分析软件栈 BDAS (Berkeley Data Analytics Stack) 的重要组成部分。
Spark 生态系统中提供的许多组件,可以满足不同的应用场景,如 Spark Core, Spark SQL, Spark Streaming, MLLib, GraphX 等。
- Spark Core 包含 Spark 的基本功能,如内存计算、任务调度、部署模式、故障恢复、存储管理等,主要面向批数据处理。
- Spark SQL 允许开发人员直接处理 RDD (Resillient Distributed Dataset),同时也可以查询 Hive, HBase 等外部数据源。其能够统一处理关系表和 RDD,使得开发人员不需要自己编写 Spark 应用程序。
- Spark Streaming 支持高吞吐量、可容错处理的实时流数据处理,其核心思路是将流数据分解成一系列短小的批处理作业,每个批处理作业都可以使用 Spark Core 进行快速处理。
- MLLib 提供常用机器学习算法的实现,包括聚类、分类、回归、协同过滤等。
- GraphX 是 Spark 中用于图计算的 API,拥有丰富的功能和运算符,能在海量数据上自如地运行复杂的图算法。
应用场景 |
时间跨度 |
其他框架 |
Spark 生态系统中的组件 |
---|---|---|---|
复杂的批量数据处理 | 小时级 | MapReduce, Hive | Spark |
基于历史数据的交互式查询 | 分钟级、秒级 | Impala, Dremel, Drill | Spark SQL |
基于实时数据流的数据处理 | 毫秒、秒级 | Storm, S4 | Spark Streaming |
基于历史数据的数据挖掘 | - | Mahout | MLlib |
图结构数据的处理 | - | Pregel, Hama | GraphX |
Spark 运行架构
基本概念
- RDD:是 Resillient Distributed Dataset(弹性分布式数据集)的简称,是分布式内存的一个抽象概念,提供了一种高度受限的共享内存模型。
- DAG:是 Directed Acyclic Graph(有向无环图)的简称,反映 RDD 之间的依赖关系。
- Executor:是运行在工作节点 (WorkerNode)的一个进程,负责运行 Task。
- Application:用户编写的 Spark 应用程序。
- Task:运行在 Executor 上的工作单元。
- Job:一个 Job 包含多个 RDD 及作用于相应 RDD 上的各种操作。
- Stage:是 Job 的基本调度单位,一个 Job 会分为多组 Task,每组 Task 被称为 Stage,或者也被称为 TaskSet,代表了一组关联的、相互之间没有 Shuffle 依赖关系的任务组成的任务集。
架构设计
- Spark 运行架构包括集群资源管理器 (Cluster Manager)、运行作业任务的工作节点 (Worker Node)、每个应用的任务控制节点 (Driver) 和每个工作节点上负责具体任务的执行进程 (Executor)。
- 资源管理器可以自带或 Mesos 或 YARN。
- 与 Hadoop MapReduce 计算框架相比,Spark 所采用的 Executor 有两个优点:
- 利用多线程来执行具体的任务,减少任务的启动开销。
- Executor 中有一个 BlockManager 存储模块,会将内存和磁盘共同作为存储设备,有效减少 IO 开销。
- 一个 Application 由一个 Driver 和若干个 Job 构成,一个 Job 由多个 Stage 构成,一个 Stage 由多个没有 Shuffle 关系的 Task 组成。
- 当执行一个 Application 时,Driver 会向集群管理器申请资源,启动 Executor,并向 Executor 发送应用程序代码和文件,然后在 Executor 上执行 Task,运行结束后,执行结果会返回给 Driver,或者写到 HDFS 或者其他数据库中。
Spark 运行基本流程
- 首先为应用构建起基本的运行环境,即由 Driver 创建一个 SparkContext,进行资源的申请、任务的分配和监控
- 资源管理器为 Executor 分配资源,并启动 Executor 进程
- SparkContext 根据 RDD 的依赖关系构建 DAG 图,DAG 图提交给 DAGScheduler 解析成 Stage,然后把一个个 TaskSet 提交给底层调度器 TaskScheduler 处理;Executor 向 SparkContext 申请 Task,Task Scheduler 将 Task 发放给 Executor 运行,并提供应用程序代码
- Task 在 Executor 上运行,把执行结果反馈给 TaskScheduler,然后反馈给 DAGScheduler,运行完毕后写入数据并释放所有资源
总体而言,Spark 运行架构具有以下特点:
- 每个 Application 都有自己专属的 Executor 进程,并且该进程在 Application 运行期间一直驻留。Executor 进程以多线程的方式运行 Task
- Spark 运行过程与资源管理器无关,只要能够获取 Executor 进程并保持通信即可
- Task 采用了数据本地性和推测执行等优化机制
RDD 运行原理
设计背景
- 许多迭代式算法(比如机器学习、图算法等)和交互式数据挖掘工具,共同之处是,不同计算阶段之间会重用中间结果。
- 目前的 MapReduce 框架都是把中间结果写入到 HDFS 中,带来了大量的数据复制、磁盘 IO 和序列化开销。
- RDD 就是为了满足这种需求而出现的,它提供了一个抽象的数据架构,我们不必担心底层数据的分布式特性,只需将具体的应用逻辑表达为一系列转换处理,不同 RDD 之间的转换操作形成依赖关系,可以实现管道化,避免中间数据存储。
RDD 概念
- 一个 RDD 就是一个分布式对象集合,本质上是一个只读的分区记录集合,每个 RDD 可分成多个分区,每个分区就是一个数据集片段,并且一个 RDD 的不同分区可以被保存到集群中不同的节点上,从而可以在集群中的不同节点上进行并行计算。
- RDD 提供了一种高度受限的共享内存模型,即 RDD 是只读的记录分区的集合,不能直接修改,只能基于稳定的物理存储中的数据集创建 RDD,或者通过在其他 RDD 上执行确定的转换操作(如 map、join 和 group by)而创建得到新的 RDD。
- RDD 提供了一组丰富的操作以支持常见的数据运算,分为“动作”(Action)和“转换”(Transformation)两种类型。
- RDD 提供的转换接口都非常简单,都是类似 map、filter、groupBy、join 等粗粒度的数据转换操作,而不是针对某个数据项的细粒度修改(不适合网页爬虫)。
- 表面上 RDD 的功能很受限、不够强大,实际上 RDD 已经被实践证明可以高效地表达许多框架的编程模型(比如 MapReduce、SQL、Pregel)。
- Spark 用 Scala 语言实现了 RDD 的 API,程序员可以通过调用 API 实现对 RDD 的各种操作。
RDD 典型的执行过程如下:
- RDD 读入外部数据源进行创建
- RDD 经过一系列的转换(Transformation)操作,每一次都会产生不同的 RDD,供给下一个转换操作使用
- 最后一个 RDD 经过“动作”操作进行转换,并输出到外部数据源图 10-8 RDD 执行过程的一个实例这一系列处理称为一个 Lineage(血缘关系),即 DAG 拓扑排序的结果
优点:惰性调用、管道化、避免同步等待、不需要保存中间结果、每次操作变得简单
RDD 特性
Spark 采用 RDD 以后能够实现高效计算的原因主要在于:
- 高效的容错性
- 现有容错机制:数据复制或者记录日志
- RDD:血缘关系、重新计算丢失分区、无需回滚系统、重算过程在不同节点之间并行、只记录粗粒度的操作
- 中间结果持久化到内存,数据在内存中的多个 RDD 操作之间进行传递,避免了不必要的读写磁盘开销
- 存放的数据可以是 Java 对象,避免了不必要的对象序列化和反序列化
RDD 之间的依赖关系
- 窄依赖表现为一个父 RDD 的分区对应于一个子 RDD 的分区或多个父 RDD 的分区对应于一个子 RDD 的分区
- 宽依赖则表现为存在一个父 RDD 的一个分区对应一个子 RDD 的多个分区
Stage 的划分
Spark 通过分析各个 RDD 的依赖关系生成了 DAG,再通过分析各个 RDD 中的分区之间的依赖关系来决定如何划分 Stage,具体划分方法是:
- 在 DAG 中进行反向解析,遇到宽依赖就断开
- 遇到窄依赖就把当前的 RDD 加入到 Stage 中
- 将窄依赖尽量划分在同一个 Stage 中,可以实现流水线计算
如上图,被分成三个 Stage,在 Stage2 中,从 map 到 union 都是窄依赖,这两步操作可以形成一个流水线操作。
流水线操作实例:
分区 7 通过 map 操作生成的分区9,可以不用等待分区8到分区10这个 map 操作的计算结束,而是继续进行 union 操作,得到分区13,这样流水线执行大大提高了计算的效率。
Stage的类型包括两种:ShuffleMapStage 和 ResultStage,具体如下:
- ShuffleMapStage:不是最终的 Stage,在它之后还有其他 Stage,所以,它的输出一定需要经过 Shuffle 过程,并作为后续 Stage 的输入;这种 Stage 是以 Shuffle 为输出边界,其输入边界可以是从外部获取数据,也可以是另一个 ShuffleMapStage 的输出,其输出可以是另一个 Stage 的开始;在一个 Job 里可能有该类型的 Stage,也可能没有该类型 Stage;
- ResultStage:最终的 Stage,没有输出,而是直接产生结果或存储。这种 Stage 是直接输出结果,其输入边界可以是从外部获取数据,也可以是另一个 ShuffleMapStage 的输出。在一个 Job 里必定有该类型 Stage。因此,一个 Job 含有一个或多个 Stage,其中至少含有一个 ResultStage。
RDD 运行过程
通过上述对 RDD 概念、依赖关系和 Stage 划分的介绍,结合之前介绍的 Spark 运行基本流程,再总结一下 RDD 在 Spark 架构中的运行过程:
- 创建 RDD 对象;
- SparkContext 负责计算 RDD 之间的依赖关系,构建 DAG;
- DAGScheduler 负责把 DAG 图分解成多个 Stage,每个 Stage 中包含了多个 Task,每个 Task 会被 TaskScheduler 分发给各个 WorkerNode 上的 Executor 去执行。
- Title: 大数据技术原理与应用 - (10). Spark
- Author: Zhanhang (Matthew) ZENG
- Link: https://zengzhanhang.com/2020/06/03/intro2BigData10/
- Released Date: 2020-06-03
- Last update: 2020-12-29
- Statement: All articles in this blog, unless otherwise stated, are based on the CC BY-NC-SA 4.0 license.