Spark research paper已经在经典的Hadoop MapReduce上规定了一个新的分布式编程模型,声称在许多情况下特别是机器学习的简化和巨大的性能提升。但是,本文中似乎缺少使用internal mechanics
揭示Resilient Distributed Datasets
Directed Acyclic Graph
{{1}}的材料。
通过调查源代码可以更好地学习吗?
答案 0 :(得分:133)
即使我一直在网上了解火花如何从RDD计算DAG并随后执行任务。
在高级别,当在RDD上调用任何操作时,Spark会创建DAG并将其提交给DAG调度程序。
DAG调度程序将运算符划分为任务阶段。阶段由基于输入数据的分区的任务组成。 DAG调度程序将运营商连接在一起。对于例如许多地图运营商可以在一个阶段进行安排。 DAG调度程序的最终结果是一组阶段。
将阶段传递给任务计划程序。任务计划程序通过集群管理器(Spark Standalone / Yarn / Mesos)启动任务。任务调度程序不知道阶段的依赖关系。
Worker在Slave上执行任务。
让我们来看看Spark如何构建DAG。
在高级别,有两种转换可以应用于RDD,即窄转换和广泛转换。宽变换基本上导致阶段边界。
缩小转换 - 不需要跨分区对数据进行混洗。例如,地图,过滤等。
广泛转型 - 要求对数据进行洗牌,例如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对象的DAG(RDD沿袭),稍后将在调用操作时使用。每个RDD都维护一个指向一个或多个父项的指针以及有关它与父项的关系类型的元数据。例如,当我们在RDD上调用val b = a.map()
时,RDD b
会保留对其父a
的引用,这是一个沿袭。
为了显示RDD的谱系,Spark提供了一种调试方法toDebugString()
。例如,在toDebugString()
RDD上执行splitedLines
将输出以下内容:
(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个分区,然后将有4组任务并行创建和提交,前提是有足够的从属/核心。下图更详细地说明了这一点:
有关更多详细信息,我建议您浏览以下YouTube视频,其中Spark创建者会详细介绍DAG和执行计划以及生命周期。
答案 1 :(得分:5)
通过以下三个组件添加了Spark 1.4
数据可视化,其中还提供了DAG
的清晰图形表示。
Spark事件的时间轴视图
执行DAG
Spark Streaming统计数据的可视化
有关详细信息,请参阅link。