互联网技术 / 互联网资讯 · 2023年11月30日 0

Spark计算原理分析

在大数据时代,Hadoop的MapReduce和YARN架构是早期的产品,主要满足了离线计算的需求,但对于实时计算却显得力不从心。为了应对这一挑战,后来的开发者们创造了Spark计算框架,大幅提升了计算效率。

Spark的计算原理

Spark的架构如下:

节点的具体介绍:

Cluster Manager:在独立模式下充当主节点,负责管理整个集群并监控Worker。在YARN模式下,则作为资源管理器,负责资源的分配,类似于YARN中的Resource Manager,像是乙方的大管家,掌控所有的计算资源。

Worker Node:实际执行计算任务的节点,接受Cluster Manager的指令,具有实际的计算资源。它还负责管理计算节点,并启动Executor或Driver。

Executor:在Worker Node上运行的进程,相当于一个项目经理,负责准备任务环境并执行任务。

Task:具体的计算单元,负责内存和磁盘资源的使用,每个Task代表一个施工项目中的具体任务。

Driver:主管任务的生成和发送给Executor,运行应用程序的main()函数,相当于甲方的指挥官。

SparkContext:与Cluster Manager交互,负责申请资源,类似于甲方的接口人。

整个交互流程如下:

甲方发起项目,创建SparkContext,SparkContext向Cluster Manager申请资源并提供需求,如CPU和内存等。Cluster Manager接着寻找Worker Node并启动Executor,并将Executor介绍给Driver;Driver根据施工图将任务拆分为多个Task,并将这些Task交给Executor执行;Executor接收Task后准备运行环境并执行,将结果反馈给Driver;Driver根据Task的执行状态持续调整后续工作,直到所有Task执行完毕。

运行流程及特点如下:

SparkContext的主要功能不仅包括任务分发和资源申请,更重要的是将RDD分解为Task并绘制DAG图。

结合上图,我们进一步分析Spark的计算过程:

首先构建Spark应用程序的运行环境,启动SparkContext;接着SparkContext向资源管理器(如Standalone、Mesos或YARN)申请Executor资源,并启用StandaloneExecutor backend;Executor向SparkContext申请Task;SparkContext将应用程序分发给Executor;同时构建DAG图,将DAG图分解为多个阶段,并将Task集发送至Task Scheduler,最后由Task Scheduler将Task发送给Executor执行;Task在Executor上运行后释放所有资源。

RDD计算案例

以下是一个关于RDD计算过程的案例分析:

在客户端,通过RDD构建一个RDD的图形,如图中第一部分Rdd1.join(Rdd2).groupBy(…).filter(…). SparkContext中的DAGScheduler会把上一步的RDD图形转换为DAG图形,如图中第二部分;TaskScheduler会将DAG图形拆分为多个Task;Cluster Manager通过YARN调度器将Task分配到各个节点的Executor中,结合相应的资源进行计算。

DAGScheduler对RDD图形的划分遵循一定的规律:

阶段的划分是触发action时,从后向前进行的,因此本图应从RDD_G开始划分。RDD_G依赖于RDD_B和RDD_F,随机决定先判断哪个依赖,但对结果没有影响。RDD_B与RDD_G属于窄依赖,因此它们处于同一个阶段,而RDD_B与它的父节点RDD_A之间是宽依赖,所以RDD_A必须单独作为一个stage1;同理,RDD_F与RDD_G也是宽依赖,因此它们不能在同一阶段,最终限制了最后一个阶段的范围,RDD_B和RDD_G组成Stage3;而RDD_F与两个父节点RDD_D和RDD_E之间是窄依赖关系,RDD_D与父节点RDD_C之间也是窄依赖,所以它们都属于同一个stage2;在执行过程中,stage1和stage2之间没有前后关系,因此可以并行执行,相应的每个stage内部的各个partition对应的task也能并行执行;stage3依赖于stage1和stage2的执行结果,只有在前两个阶段完成后才能启动stage3;正如前面提到的,Spark的Task有两种类型:ShuffleMapTask和ResultTask,后者在DAG的最后阶段推送给Executor,其余阶段推送的都是ShuffleMapTask。在这个案例中,stage1和stage2生成的都是ShuffleMapTask,而stage3则产生ResultTask;尽管阶段的划分是从后向前进行的,但依赖逻辑判断结束后,真正创建阶段是从前往后进行的。换句话说,若以阶段的ID作为标识,先执行的阶段的ID必须小于后执行的阶段ID。就本案例而言,stage1和stage2的ID都应小于stage3,而stage1和stage2的ID的大小则是随机的,由前面的步骤决定。

Executor作为最终执行task的实体,将Task的执行结果反馈给Driver,并根据结果的大小采取不同的策略:

如果结果大于MaxResultSize(默认1G),则直接丢弃;如果结果“较大”,超出配置的frameSize(默认10M),则以taskId为键存入BlockManager,否则,全部返回给Driver。