Spark 的架构原理
本文旨在记录自己所学的大数据知识。本文素材来源于李智慧老师的《从0开始学大数据》,李老师讲的大数据课程既有教相关知识的,也有教我们如何学习,如何思考的,讲的非常好。
Spark 也遵循移动计算比移动数据更划算这一大数据计算基本原则
相关概念:计算阶段,依赖关系,DAG,Spark应用,任务集合
一、Spark的计算阶段
1、Spark计算本质上也是Map和reduce组成的。对比MapReduce僵化地把运行划分成一个Map和一个Reduce。Spark的计算可以由多个Map和多个Reduce组成,Map根据业务需求把计算任务划分为多个阶段,每个阶段根据依赖关系组成一个DAG(有向无环图),Spark任务调度器根据DAG依赖关系进行运算。举个栗子,有些回归算法需要进行多个迭代计算,产生数万个计算阶段,这些计算阶段可以在一个Spark应用中处理,如果使用MapReduce处理,则需要产生数万个MapReduce。
2、DAG依赖,即有向无环图。
1⃣️依赖是有向的,不能组成一个环形依赖,环形依赖会进入死循环。
2⃣️被依赖的阶段要先执行完,依赖的阶段才能开始执行。Spark执行自然会沿着依赖关系执行。
栗子:下图是一个DAG,划分为3个阶段,阶段3依赖阶段1和阶段2。阶段1和阶段2互相不依赖。只需要建立好依赖关系,计算时就能按顺序执行,阶段1和阶段2运行完成以后,阶段3才能开始执行。更多阶段运行同理。
上图这个DAG中各个阶段的伪代码如下:
rddB = rddA.groupBy(key)
rddD = rddC.map(func)
rddF = rddD.union(rddE)
rddG = rddB.join(rddF)
所以,可以看到Spark运算的核心是DAG,有了DAG,就可以把它根据依赖关系划分为各个有序计算阶段,每个阶段又根据要处理的数据量生成相应的任务集合(TaskSet),每一个任务分配一个任务进程去执行,Spark就实现了大数据分布式计算了。
3⃣️具体地,生成DAG的组件是DAGScheduler。DAGScheduer根据程序代码生成DAG,然后把程序分发到分布式集群上运行,各个运算阶段根据依赖关系执行。
4⃣️阶段依赖中分为两种依赖,宽依赖和窄依赖。经过shuffle过程的依赖为宽依赖,如阶段2和阶段3之间,rddG和rddF之间是宽依赖。不经过shuffle阶段的依赖叫做窄依赖,如阶段1和阶段3之间,rddG和rddB之间的是窄依赖。
3:那么Spark划分阶段的依据是什么?
不是计算函数,有些函数会产生新阶段,有些不会。从图中可以观察出是shuffle。如A和B之间被shuffle切开,shuffle之前的算一个阶段;F和G之间被shuffle切开,shuffle之前的即CDEF算一个阶段。整个运算要执行完B和F需要合并成G,这算一个大的阶段。
4:同样经过shuffle,为什么Spark比MapReduce更加高效?
1⃣️spark不固化为一个Map和一个Reduce,可以根据业务需求组合多个Map、Reduce来形成一个连贯的计算任务。更加灵活,更加适合复杂的计算任务。MapReduce则固化为一个Map和一个Reduce,执行复杂任务时需要多个MapReduce组合。
2⃣️spark能使用内存就不会使用磁盘,MapReduce的job和job之间的数据交互都是通过磁盘的,spark的一个job和另一个job本身就是同属一个计算任务,所以job和job之间的数据交互优先使用磁盘交互,所以spark更加快。
二、Spark作业管理
Spark中RDD函数有两种,一种是转换(transform)函数,一种是action函数。
转换函数:调用以后还是返回一个RDD,spark计算逻辑主要通过转换函数完成。
action函数:调用以后返回一个job,调用以后马上会运行。
Spark的DAGScheduler在遇到shuffle的时候会生成一个计算阶段,在遇到action函数时会生成一个作业(job).
关于作业、计算阶段、任务的依赖和时间的先后,如下图:
横轴是时间,纵轴是任务。两条粗黑线之间是作业,两条细黑线之间是计算阶段,细小红线是任务。
一个作业至少包含一个计算阶段,一个计算阶段包含多个任务。
那么Spark的作业管理究竟跟spark的函数有什么关系呢?
spark的作业是DAGScheduler根据代码(函数)来生成的。即DAG(有向无环图)--> 依赖关系 --> 计算阶段 --> 计算任务。
得到计算任务后,spark任务调度会以任务为单位,把各个任务分配到不同的机器上面执行。
三、Spark的执行过程(运行流程)
Spark支持几种部署模式:standalone、Yarn、Mesos、Kubernetes。几种部署模式的执行过程都一样,只是角色的名字不同。下面介绍Spark的执行过程。
上图为Spark部署图。DriverProgram是Spark的客户端程序,是一个JVM应用。Driver Program是整个运行过程的核心。
步骤:
1、客户端Driver Program中SparkContext调用DAGScheduler计算得出DAG图,从而最终得到作业的最小执行单元——任务。
2、Driver Program带着主机地址等信息向Cluster Manager请求计算资源。
3、Cluster Manager向集群中的所有Worker发送通知,告知它们Driver Program的地址信息。
4、收到通知的Worker会根据主机地址注册到Driver Program。并且根据自身的空闲资源向Cluster Manager通报自己能认领的任务数。Driver Program根据DAG图向已注册的Worker分配任务。
5、Worker收到任务后,会启动Executor进程准备执行任务。Executor会先检查自身是否存在Driver 的任务程序(作业jar包),如果不存在的话会先向Driver Program下载任务程序,通过Java反射加载程序并执行。
总结,Spark相比MapReduce来说有三个特性,
1、Spark的编程模型更加灵活、高效。
2、DAG切分的多阶段比多个MapReduce速度快得多。
3、Spark优先使用内存进行数据中间交换,速度更快。