参见我的倔金
前言:spark学习个人总结 。主要参考已有的精品教程,部分加上自己的理解总结。引用未注明部分请联系更改。
一、Spark简介
spark是由伯克利于2009年开发,是基于内存计算的大数据并行计算框架,可用于构建大型的、低延迟的数据分析应用程序。2013年,Spark加入Apache孵化器项目。如今已成为Apache软件基金会最重要的三大分布式计算系统开源项目之一(即Hadoop、Spark、Storm)。2014年打破了Hadoop保持的基准排序(Sort Benchmark)纪录。
特点
- 运行速度快(相比hadoop)
- 易用性:支持scala、java、python等多种语言; API简单易用;可以用spark shell交互
- 通用性:技术栈完整强大;有SQL查询、流计算、机器学习算法、图算法组件,无缝对接
- 部署灵活:可以独立集群运行,也可结合hadoop
对比hadoop
- 运行更快:spark基于内存运算,中间结果在内存;hadoop基于磁盘
- 运行模式更灵活;不仅用mapreduce模式,还有其它
- 调度机制更优:基于DAG的任务调度机制,优于MapReduce的迭代执行机制
spark生态
Spark的生态系统主要包含了Spark Core、Spark SQL、Spark Streaming、MLLib和GraphX 等组件;Spark生态系统已经成为伯克利数据分析软件栈BDAS(Berkeley Data Analytics Stack)的重要组成部分。BDAS架构如下
二、Spark运行架构
架构设计
Spark运行架构包括集群资源管理器(Cluster Manager)、运行作业任务的工作节点(Worker Node)、每个应用的任务控制节点(Driver)和每个工作节点上负责具体任务的执行进程(Executor)
架构图如下:
spark运行基本流程
- spark submit提交应用程序后,由任务控制节点(Driver)为改应用创建一个SparkContext;SparkContext负责和资源管理器(Cluster Manager)的通信以及进行资源的申请、任务的分配和监控等。
- SparkContext会向Cluster Manager注册并申请运行Executor的资源;然后Cluster Manager会创建一个Executor进程(每个应用都有自己专属的Executor进程,并且该进程在应用运行期间一直驻留);Executor运行情况定期汇报给Cluster Manager
-
- SparkContext根据RDD的依赖关系构建DAG图,DAG图提交给DAG调度器(DAGScheduler)进行解析
- DAGScheduler将DAG图分解成多个“阶段”(每个阶段都是一个任务集),并且计算出各个阶段之间的依赖关系,然后把一个个“任务集”提交给底层的任务调度器(TaskScheduler)进行处理
- Executor进程向SparkContext申请任务,TaskScheduler将任务分发给Executor进程运行,同时,SparkContext将应用程序代码发放给Executor进程
- 任务在Executor上运行,把执行结果反馈给TaskScheduler,然后反馈给DAG调度器,运行完毕后写入数据并释放所有资源。
流程图如下:
三、RDD运行原理
参考1 RDD原始论文
1.设计缘起
- 实际中许多迭代式算法(机器学习、图计算)等需要中间结果给后续计算,但MapReduce模式将中间结果保存到HDFS中,有大量磁盘IO、数据复制等开销。
- 谷歌09年提出的Pregel图计算框架 将结果保存到内存中,但只支持特定的计算模式(不通用
- RDD应运而生。提供一个抽象的数据架构
2.RDD概念
- RDD是弹性分布式数据集(Resilient Distributed Dataset)的简称,是一个抽象概念(类比cache中的block),是spark运算的最基本单元,其实是内存中的一部分
- 一个RDD是多个分区构成的集合,每个分区是内存上的一个数据集片段
- 一个RDD的多个分区可以分布在集群的不同节点上,这样可以并行计算
- RDD是只读的记录分区的集合,不能直接修改
- 只能基于稳定的物理存储中的数据集来创建RDD,或者通过在其他RDD上执行确定的转换操作(如map、join和groupBy)而创建得到新的RDD
- RDD提供了一组丰富的操作以支持常见的数据运算,分为“行动”(Action)和“转换”(Transformation)两种类型,前者用于执行计算并指定输出的形式,后者指定RDD之间的相互依赖关系
- 转换操作(比如map、filter、groupBy、join等);行动操作(比如count、collect等)
3.RDD执行过程
- 输入数据,创建RDD
- RDD每次经过一个Transformation操作,都会产生不同的RDD,供给下一个Transformation使用
- RDD遇到Action操作就会开始计算
- 注意:RDD的执行过程中,真正的计算发生在RDD的“行动”操作,对于“行动”之前的所有“转换”操作,Spark只是记录下“转换”操作应用的一些基础数据集以及RDD生成的轨迹,即相互之间的依赖关系,而不会触发真正的计算。
4.RDD之间的依赖关系
每个RDD有多个分区,根据父RDD分区到子RDD分区的映射类型分为窄依赖和宽依赖。
- 窄依赖:一个父RDD的分区对应于一个子RDD的分区,或多个父RDD的分区对应于一个子RDD的分区
- 宽依赖: 存在一个父RDD的一个分区对应一个子RDD的多个分区
- 如果父RDD的一个分区只被一个子RDD的一个分区所使用就是窄依赖,否则就是宽依赖。窄依赖典型的操作包括map、filter、union等,宽依赖典型的操作包括groupByKey、sortByKey等
如图所示
5.RDD运行过程
根据RDD之间不同依赖关系划分阶段
- Spark通过分析各个RDD的依赖关系生成了DAG,再通过分析各个RDD中的分区之间的依赖关系来决定如何划分阶段
- 在DAG中进行反向解析,遇到宽依赖就断开,遇到窄依赖就把当前的RDD加入到当前的阶段中
- 将窄依赖尽量划分在同一个阶段中,可以实现流水线计算
RDD运行过程如图所示: