一、Spark 是什么
Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用分布式并行计算框架。Spark拥有hadoop MapReduce所具有的优点,但和MapReduce 的最大不同之处在于Spark是基于内存的迭代式计算——Spark的Job处理的中间输出结果可以保存在内存中,从而不再需要读写HDFS,除此之外,一个MapReduce 在计算过程中只有map 和reduce 两个阶段,处理之后就结束了,而在Spark的计算模型中,可以分为n阶段,因为它内存迭代式的,我们在处理完一个阶段以后,可以继续往下处理很多个阶段,而不只是两个阶段。
因此Spark能更好地适用于数据挖掘与机器学习等需要迭代的MapReduce的算法。其不仅实现了MapReduce的算子map 函数和reduce函数及计算模型,还提供更为丰富的算子,如filter、join、groupByKey等。是一个用来实现快速而同用的集群计算的平台。
二、spark 的框架设计
spark 框架如图1 所示 :
从图1中可以看到,所有的Spark应用程序都离不开SparkContext和Executor两部分,Executor负责执行任务,运行Executor的机器称为Worker节点,SparkContext由用户程序启动,通过资源调度模块和Executor通信。SparkContext和Executor这两部分的核心代码实现在各种运行模式中都是公用的,在它们之上,根据运行部署模式的不同,包装了不同调度模块以及相关的适配代码。
具体来说,以SparkContext为程序运行的总入口,在SparkContext的初始化过程中,Spark会分别创建DAGScheduler作业调度和TaskScheduler任务调度两级调度模块。其中作业调度模块是基于任务阶段的高层调度模块,它为每个Spark作业计算具有依赖关系的多个调度阶段(通常根据shuffle来划分),然后为每个阶段构建出一组具体的任务(通常会考虑数据的本地性等),然后以TaskSets(任务组)的形式提交给任务调度模块来具体执行。而任务调度模块则负责具体启动任务、监控和汇报任务运行情况。
备注:在上述框架图中的一些术语解释如下:
Cluster Manager:在集群上获取资源的外部服务。目前有三种类型:
1. Standalone, Spark原生的资源管理;
2. Apache Mesos, 和Hadoop Mapreduce兼容性良好的资源调度框架;
Application: 用户编写的应用应用程序。
Driver: Application中运行main函数并创建的SparkContext, 创建SparkContext的目的是和集群的ClusterManager通讯,进行资源的申请、任务的分配和监控等。所以,可以用SparkContext代表Driver
Worker:集群中可以运行Application代码的节点。
Executor: 某个Application在Worker上面的一个进程,该进程负责执行某些Task,并负责把数据存在内存或者磁盘上。每个Application都各自有一批属于自己的Executor。
Task:被送到Executor执行的工作单元,和Hadoop MapReduce中的MapTask和ReduceTask一样,是运行Application的基本单位。多个Task组成一个Stage,而Task的调度和管理由TaskScheduler负责。
Job:包含多个Task组成的并行计算,往往由Spark Action触发产生。一个Application可以产生多个Job。
Stage:每个Job的Task被拆分成很多组Task, 作为一个TaskSet,命名为Stage。Stage的调度和划分由DAGScheduler负责。Stage又分为Shuffle Map Stage和Result Stage两种。Stage的边界就在发生Shuffle的地方。
**RDD:**Spark的基本数据操作抽象,可以通过一系列算子进行操作。RDD是Spark最核心的东西,可以被分区、被序列化、不可变、有容错机制,并且能并行操作的数据集合。存储级别可以是内存,也可以是磁盘。
DAGScheduler:根据Job构建基于Stage的DAG(有向无环任务图),并提交Stage给TaskScheduler
TaskScheduler:将Stage提交给Worker(集群)运行,每个Executor运行什么在此分配。
**共享变量:**Spark Application在整个运行过程中,可能需要一些变量在每个Task中都使用,共享变量用于实现该目的。Spark有两种共享变量:一种缓存到各个节点的广播变量;一种只支持加法操作,实现求和的累加变量。
宽依赖:或称为ShuffleDependency, 宽依赖需要计算好所有父RDD对应分区的数据,然后在节点之间进行Shuffle。
窄依赖:或称为NarrowDependency,指某个RDD,其分区partition x最多被其子RDD的一个分区partion y依赖。窄依赖都是Map任务,不需要发生shuffle。因此,窄依赖的Task一般都会被合成在一起,构成一个Stage。
三、spark 的工作流程原理
spark 的工作原理图 如图2 所示
根据图2 可以把spark的工作流程描述如下:
a. 构建Spark Application的运行环境(启动SparkContext)
b. SparkContext在初始化过程中分别创建DAGScheduler作业调度和TaskScheduler任务调度
两级调度模块
c. SparkContext向资源管理器(可以是Standalone、Mesos、Yarn)申请运行Executor资源;
d. 由资源管理器分配资源并启动StandaloneExecutorBackend,executor,之后向SparkContext申请Task;
e. DAGScheduler将job 划分为多个stage,并将Stage提交给TaskScheduler;
g. Task在Executor上运行,运行完毕释放所有资源。
详解:
在我们使用spark-submit 提交了我们的应用程序的时候,提交spark的运用机器会通过反射的方式,创建和构造一个Driver进程,Driver进程执行Application程序,根据sparkConf中的配置初始SparkContext,在SparkContext 初始化的过程中会启动DAGScheduler和taskScheduler两个调度模块,同时taskSheduler通过后台进程,向Master注册Application,Master接到到了Application的注册请求之后,会使用自己的资源调度算法,在spark集群的worker上,通知worker为application启动多个Executor。之后Executor会向taskScheduler反向注册。Driver完成SparkContext初始化,并继续执行application程序,当执行到Action时,就会创建Job。并且由DAGScheduler将Job划分多个Stage,每个Stage 由TaskSet 组成,并将TaskSet提交给taskScheduler,taskScheduler把TaskSet中的task依次提交给Executor,Executor在接收到task之后,会使用taskRunner来封装task(TaskRuner主要将我们编写程序,也就是我们编写的算子和函数进行拷贝和反序列化),然后,从Executor的线程池中取出一个线程来执行task。就这样Spark的每个Stage被作为TaskSet提交给Executor执行,每个Task对应一个RDD的partition,执行我们的定义的算子和函数。直到所有操作执行完为止。
四、spark 的核心编程操作
在我们的实际开发中需要我们处理的核心编程如下:
1、初始定义的RDD,即你要定义的RDD来自于哪里,比如是HDFS,还是Linux系统中的本地文件或者是集合
2、定义对RDD 的计算操作,在spark 中通常称为算子。比如:map 、groupByKey 、reduce 等
3、对步骤2中产生的新RDD 进行循环往复定义其它的算子操作
4、将最终获得的数据集保存起来。比如存储在数据库或者HDFS上
五、spark 的核心RDD
1、RDD的定义
RDD(Resilient Distributed Datasets) 弹性分布式数据集。 其详细描述如下:
a、RDD在抽象上来说是一种元素集合,包含了数据。它是被分区的,分为多个分区,每个分区分布在集群中的不同节点上,从而让RDD中的数据可以被并行操作。(分布式数据集)
b、RDD的数据默认情况下存放在内存中的,但是在内存资源不足时,Spark会自动将RDD数据写入磁盘。比如每个节点最多放5万数据,结果你每个partition是10万数据。那么就会把partition中的部分数据写入磁盘上,进行保存。(弹性)
2、RDD操作特性
RDD将操作分为两类:transformation与action。无论执行了多少次transformation操作,RDD都不会真正执行运算,只有当action操作被执行时,运算才会触发。而在RDD的内部实现机制中,底层接口则是基于迭代器的,从而使得数据访问变得更高效,也避免了大量中间结果对内存的消耗。
3、RDD的容错特性
RDD最重要的特性就是,提供了容错性,可以自动从节点失败中恢复过来。即如果某个节点上的RDD partition,因为节点故障,导致数据丢了,那么RDD会自动通过自己的数据来源重新计算该partition。这一切对使用者是透明的。