【发布时间】:2015-08-21 20:54:31
【问题描述】:
我知道 Spark 可以使用 Scala、Python 和 Java 进行操作。此外,RDD 用于存储数据。
但是请解释一下,Spark 的架构是什么以及它在内部是如何工作的。
【问题讨论】:
标签: apache-spark
我知道 Spark 可以使用 Scala、Python 和 Java 进行操作。此外,RDD 用于存储数据。
但是请解释一下,Spark 的架构是什么以及它在内部是如何工作的。
【问题讨论】:
标签: apache-spark
Spark 围绕弹性分布式数据集 (RDD) 的概念展开,RDD 是可以并行操作的元素的容错集合。 RDD 支持两种类型的操作:转换(从现有数据集创建新数据集)和操作(在对数据集运行计算后将值返回给驱动程序)。
Spark 将 RDD 转换转换为称为 DAG(有向无环图)的东西并开始执行,
在高层次上,当在 RDD 上调用任何操作时,Spark 会创建 DAG 并提交给 DAG 调度程序。
DAG 调度器将算子划分为任务的阶段。一个阶段由基于输入数据分区的任务组成。 DAG 调度程序将操作员流水线化在一起。例如。许多地图操作员可以在一个阶段进行调度。 DAG 调度器的最终结果是一组阶段。
这些阶段被传递到任务计划程序。任务调度程序通过集群管理器(Spark Standalone/Yarn/Mesos)启动任务。任务调度器不知道阶段的依赖关系。
Worker/Slave 执行任务。
让我们来看看 Spark 如何构建 DAG。
在高层次上,可以对 RDD 应用两种变换,即窄变换和宽变换。宽变换基本上会产生阶段边界。
窄转换 - 不需要在分区之间打乱数据。例如map、filter等。
宽变换 - 需要对数据进行shuffle,例如reduceByKey等
让我们举个例子,计算每个严重级别出现多少日志消息。
以下是以严重级别开头的日志文件:
INFO I'm Info message
WARN I'm a Warn message
INFO I'm another Info message
并创建以下 Scala 代码以提取相同的内容:
val input = sc.textFile("log.txt")
val splitedLines = input.map(line => line.split(" "))
.map(words => (words(0), 1))
.reduceByKey{(a,b) => a + b}
此命令序列隐式定义了 RDD 对象(RDD 沿袭)的 DAG,稍后将在调用操作时使用该 DAG。每个 RDD 都维护一个指向一个或多个父节点的指针,以及关于它与父节点的关系类型的元数据。例如,当我们在 RDD 上调用 val b = a.map() 时,RDD b 会保留对其父 a 的引用,这是一个沿袭。
为了显示一个 RDD 的血统,Spark 提供了一个调试方法 toDebugString() 方法。例如,在splitedLines RDD上执行toDebugString(),会输出如下:
(2) ShuffledRDD[6] at reduceByKey at <console>:25 []
+-(2) MapPartitionsRDD[5] at map at <console>:24 []
| MapPartitionsRDD[4] at map at <console>:23 []
| log.txt MapPartitionsRDD[1] at textFile at <console>:21 []
| log.txt HadoopRDD[0] at textFile at <console>:21 []
第一行(从底部开始)显示了输入 RDD。我们通过调用sc.textFile() 创建了这个RDD。请参阅下面从给定 RDD 创建的 DAG 图的更多图解视图。
构建 DAG 后,Spark 调度程序会创建一个物理执行计划。如上所述,DAG 调度程序将图拆分为多个阶段,这些阶段是基于转换创建的。狭窄的转换将被组合在一起(流水线)成一个阶段。因此对于我们的示例,Spark 将创建一个两阶段执行,如下所示:
然后,DAG 调度程序将阶段提交到任务调度程序。提交的任务数量取决于textFile 中存在的分区数量。 Fox 示例假设我们在此示例中有 4 个分区,那么如果有足够的 slaves/cores,将有 4 组任务并行创建和提交。下图更详细地说明了这一点:
有关更多详细信息,我建议您观看以下 YouTube 视频,其中 Spark 创建者提供了有关 DAG 以及执行计划和生命周期的详细信息。
【讨论】:
以下是我将使用的 Apache Spark 的一些行话。
工作:-一段代码,它从 HDFS 或本地读取一些输入,对数据执行一些计算并写入一些输出数据。
阶段:-工作分为阶段。阶段分为 Map 或 reduce 阶段(如果您曾在 Hadoop 上工作并想要关联,则更容易理解)。阶段是根据计算边界划分的,所有计算(算子)不能在一个阶段中更新。它发生在许多阶段。
任务:- 每个阶段都有一些任务,每个分区一个任务。一个任务在一个执行器(机器)上的一个数据分区上执行。
DAG:- DAG 代表有向无环图,在当前上下文中,它是运算符的 DAG。
执行者:-负责执行任务的进程。
驱动程序:-负责在 Spark 引擎上运行作业的程序/进程
Master:-驱动程序运行的机器
Slave:-Executor程序运行的机器
spark 中的所有作业都包含一系列运算符并在一组数据上运行。作业中的所有运算符都用于构造 DAG(有向无环图)。通过在可能的情况下重新排列和组合运算符来优化 DAG。例如,假设您必须提交一个 Spark 作业,其中包含一个 map 操作,然后是一个 filter 操作。 Spark DAG 优化器会重新排列这些运算符的顺序,因为过滤会减少要进行映射操作的记录数。
Spark 的代码库很小,系统分为不同的层。每一层都有一些职责。这些层是相互独立的。
Spark 缓存要处理的数据,这让我比 hadoop 快 100 倍。 Spark 是高度可配置的,并且能够利用 Hadoop 生态系统中已经存在的现有组件。这使得 spark 呈指数级增长,并且在短时间内,许多组织已经在生产中使用它。
【讨论】: