一。Spark的概述和特点

1)Spark背景:MapReduce局限性

MapReduce框架局限性
处理效率低效
Map中间结果写磁盘, Reduce写HDFS, 多个MR之间通过HDFS交换数据;
任务调度和启动开销大;
无法充分利用内存
Map端和Reduce端均需要排序
不适合迭代计算(如机器学习、 图计算等) , 交互式处理(数据挖掘)
和流式处理(点击日志分析)
MapReduce编程不够灵活
仅支持Map和Reduce两种操作
尝试函数式编程风格

产生背景:大统一系统

Spark的基础知识 - 图3

2)Spark特点

高效(比MapReduce快10~100倍)
内存计算引擎, ᨀ供Cache机制来支持需要反复迭代计算或
者多次数据共享, 减少数据读取的IO开销
DAG引擎, 减少多次计算之间中间结果写到HDFS的开销
使用多线程池模型来减少task启动开稍, shuffle过程中避免
不必要的sort操作以及减少磁盘IO操作
易用
提供了丰富的API, 支持Java, Scala, Python和R四种语言
代码量比MapReduce少2~5倍
与Hadoop集成
读写HDFS/Hbase
与YARN集成

二。Spark核心概念—RDD
RDD: Resilient Distributed Datasets, 弹性分布式
数据集
分布式存储在集群的各个节点上(每一部分称为一个
Partition)
可以选择不同的存储方式(磁盘或内存)
可以由一个RDD生成另外一个RDD(转换操作)
数据丢失后可以自动恢复

1、RDD特点

RDD表示只读的分区的数据集,对RDD进行改动,只能通过RDD的转换操作,由一个RDD得到一个新的RDD,新的RDD包含了从其他RDD衍生所必需的信息。RDDs之间存在依赖,RDD的执行是按照血缘关系延时计算的。如果血缘关系较长,可以通过持久化RDD来切断血缘关系。

1.1 分区

如下图所示,RDD逻辑上是分区的,每个分区的数据是抽象存在的,计算的时候会通过一个compute函数得到每个分区的数据。如果RDD是通过已有的文件系统构建,则compute函数是读取指定文件系统中的数据,如果RDD是通过其他RDD转换而来,则compute函数是执行转换逻辑将其他RDD的数据进行转换。

Spark的基础知识 - 图41.2 只读

如下图所示,RDD是只读的,要想改变RDD中的数据,只能在现有的RDD基础上创建新的RDD。
Spark的基础知识 - 图5
由一个RDD转换到另一个RDD,可以通过丰富的操作算子实现,不再像MapReduce那样只能写map和reduce了,如下图所示。
Spark的基础知识 - 图6
RDD的操作算子包括两类,一类叫做transformations,它是用来将RDD进行转化,构建RDD的血缘关系;另一类叫做actions,它是用来触发RDD的计算,得到RDD的相关计算结果或者将RDD保存的文件系统中。下图是RDD所支持的操作算子列表。

Spark的基础知识 - 图71.3 依赖

RDDs通过操作算子进行转换,转换得到的新RDD包含了从其他RDDs衍生所必需的信息,RDDs之间维护着这种血缘关系,也称之为依赖。如下图所示,依赖包括两种,一种是窄依赖,RDDs之间分区是一一对应的,另一种是宽依赖,下游RDD的每个分区与上游RDD(也称之为父RDD)的每个分区都有关,是多对多的关系。
Spark的基础知识 - 图8
通过RDDs之间的这种依赖关系,一个任务流可以描述为DAG(有向无环图),如下图所示,在实际执行过程中宽依赖对应于Shuffle(图中的reduceByKey和join),窄依赖中的所有转换操作可以通过类似于管道的方式一气呵成执行(图中map和union可以一起执行)。
Spark的基础知识 - 图9

1.4 缓存

如果在应用程序中多次使用同一个RDD,可以将该RDD缓存起来,该RDD只有在第一次计算的时候会根据血缘关系得到分区的数据,在后续其他地方用到该RDD的时候,会直接从缓存处取而不用再根据血缘关系计算,这样就加速后期的重用。如下图所示,RDD-1经过一系列的转换后得到RDD-n并保存到hdfs,RDD-1在这一过程中会有个中间结果,如果将其缓存到内存,那么在随后的RDD-1转换到RDD-m这一过程中,就不会计算其之前的RDD-0了。

Spark的基础知识 - 图10

1.5 checkpoint

虽然RDD的血缘关系天然地可以实现容错,当RDD的某个分区数据失败或丢失,可以通过血缘关系重建。但是对于长时间迭代型应用来说,随着迭代的进行,RDDs之间的血缘关系会越来越长,一旦在后续迭代过程中出错,则需要通过非常长的血缘关系去重建,势必影响性能。为此,RDD支持checkpoint将数据保存到持久化的存储中,这样就可以切断之前的血缘关系,因为checkpoint后的RDD不需要知道它的父RDDs了,它可以从checkpoint处拿到数据。

三。Spark的运营模式

spark应用涉及的一些基本概念:

1.mater:主要是控制、管理和监督整个spark集群

2.client:客户端,将用应用程序提交,记录着要业务运行逻辑和master通讯。

3.sparkContext:spark应用程序的入口,负责调度各个运算资源,协调各个work node上的Executor。主要是一些记录信息,记录谁运行的,运行的情况如何等。这也是为什么编程的时候必须要创建一个sparkContext的原因了。

4.Driver Program:每个应用的主要管理者,每个应用的老大,有人可能问不是有master么怎么还来一个?因为master是集群的老大,每个应用都归老大管,那老大疯了。因此driver负责具体事务运行并跟踪,运行Application的main()函数并创建sparkContext。

5.RDD:spark的核心数据结构,可以通过一系列算子进行操作,当Rdd遇到Action算子时,将之前的所有的算子形成一个有向无环图(DAG)。再在spark中转化成为job,提交到集群执行。一个app可以包含多个job

6.worker Node:集群的工作节点,可以运行Application代码的节点,接收mater的命令并且领取运行任务,同时汇报执行的进度和结果给master,节点上运行一个或者多个Executor进程。

7.exector:为application运行在workerNode上的一个进程,该进程负责运行Task,并且负责将数据存在内存或者磁盘上。每个application都会申请各自的Executor来处理任务。

spark应用(Application)执行过程中各个组件的概念:

1.Task(任务):RDD中的一个分区对应一个task,task是单个分区上最小的处理流程单元。

2.TaskSet(任务集):一组关联的,但相互之间没有Shuffle依赖关系的Task集合。

3.Stage(调度阶段):一个taskSet对应的调度阶段,每个job会根据RDD的宽依赖关系被切分很多Stage,每个stage都包含 一个TaskSet。

4.job(作业):由Action算子触发生成的由一个或者多个stage组成的计算作业。

5.application:用户编写的spark应用程序,由一个或者多个job组成,提交到spark之后,spark为application分派资源,将程序转换并执行。

6.DAGScheduler:根据job构建基于stage的DAG,并提交stage给TaskScheduler。

7.TaskScheduler:将Taskset提交给Worker Node集群运行并返回结果。

spark基本概念之间的关系

Spark的基础知识 - 图11

一个Application可以由一个或者多个job组成,一个job可以由一个或者多个stage组成,其中stage是根据宽窄依赖进行划分的,一个stage由一个taskset组成,一个TaskSET可以由一个到多个task组成。

应用提交与执行

spark使用driver进程负责应用的解析,切分Stage并且调度task到Executor执行,包含DAGscheduler等重要对象。Driver进程的运行地点有如下两种:

1.driver进程运行在client端,对应用进行管理监控。

2.Master节点指定某个Worker节点启动Driver进程,负责监控整个应用的执行。

driver运行在client

Spark的基础知识 - 图12

用户启动Client端,在client端启动Driver进程。在Driver中启动或实例化DAGScheduler等组件。

1.driver在client启动,做好准备工作,计划好任务的策略和方式(DAGScheduler)后向Master注册并申请运行Executor资源。

2.Worker向Master注册,Master通过指令让worker启动Executor。

3.worker收到指令后创建ExecutorRunner线程,进而ExecutorRunner线程启动executorBackend进程。

4.ExecutorBackend启动后,向client端driver进程内的SchedulerBackend注册,这样dirver进程就可以发现计算资源了。

5.Driver的DAGScheduler解析应用中的RDD DAG并生成相应的Stage,每个Stage包含的TaskSet通过TaskScheduler分配给Executor,在Exectutor内部启动线程池并行化执行Task,同事driver会密切注视,如果发现哪个execuctor执行效率低,会分配其他exeuctor顶替执行,观察谁的效率更高(推测执行)。

6.计划中的所有stage被执行完了之后,各个worker汇报给driver,同事释放资源,driver确定都做完了,就向master汇报。同时driver在client上,应用的执行进度clinet也知道了。

Driver运行在Worker节点

Spark的基础知识 - 图13

用户启动客户端,客户端提交应用程序给Master

1.Master调度应用,指定一个worker节点启动driver,即Scheduler-Backend。

2.worker接收到Master命令后创建driverRunner线程,在DriverRunner线程内创建SchedulerBackend进程,Dirver充当整个作业的主控进程。

3.Master指定其他Worker节点启动Exeuctor,此处流程和上面相似,worker创建ExecutorRunner线程,启动ExecutorBackend进程。

4.ExecutorBackend启动后,向client端driver进程内的SchedulerBackend注册,这样dirver进程就可以发现计算资源了。

5.Driver的DAGScheduler解析应用中的RDD DAG并生成相应的Stage,每个Stage包含的TaskSet通过TaskScheduler分配给Executor,在Exectutor内部启动线程池并行化执行Task,同事driver会密切注视,如果发现哪个execuctor执行效率低,会分配其他exeuctor顶替执行,观察谁的效率更高(推测执行)。

6.计划中的所有stage被执行完了之后,各个worker汇报给driver,同事释放资源,driver确定都做完了,就向master汇报。客户也会跳过master直接和drive通讯了解任务的执行进度。