Spark源码分析心得

要想学习理解一款流行分布式系统的源码不是一件容易的事情,一定要多次迭代,看无数遍并且领悟其设计思想。第一次看不要纠结于细节,每次迭代过程中增加一点点细节的理解,最终达到豁然开朗的地步。

学习优秀的源代码是提高自身技能的最好途径,比做无数个低水平的项目效果要显著的多,好了,闲话少说,让我们试图来理解Spark的世界吧。

1、大框架

首先要掌握几个基本概念,Spark是分布式计算框架,核心思想是通过将计算任务尽量分配到源数据一致的机器上执行,降低网络延时;同时引入Dag图依赖关系生成一系列计算任务,当然缓存等机制是不可避免要用到的,为了提高性能嘛。

大部分分布式计算的核心思想是类似的,通过成熟的分布式框架在集群间通信和同步消息,提供横向扩展能力,满足大数据计算的需求。在Spark中具体的分布式消息传递是通过Akka模块来支持的。

核心类:

SparkContext,DagSchedule,TaskScheduleImp(TaskSchedule的实现),Stage,Task,TaskDescription,TaskInfo,RDD,BlockManager等

(1)SparkContext

创建spark任务主要是通过它来完成的,Spark程序上下文,里面包含了DagSchedule,TaskSchedule,BlockManager等等。

(2)DagSchedule

矢量图计算,解析整个Spark任务生成Stage调用树,每个Stage的划分主要是看该Stage是否包含Shuffle过程来决定,Stage在调用的时候生成TaskSet,并通过TaskSchedule分配到具体的Executor上,每个TaskSet包含1到多个Task,Task具体分成ResultTask和ShuffleResultTask两种,两种的区别从命名上就可以区分出来,前者直接计算得到结果,后者是和Shuffle过程相关的。

(3)TaskScheduleImp

通过具体的TaskScheduleEndpoint在集群间通信,发布任务等。

与集群通信是通过TaskScheduleEndpoint来执行的。最常用的是CoarseGrainedSchedulerBackend

(4)Executor

执行单元,一般每台集群机器会分配一个Executor,每个Executor管理本地的多个TaskSet。

Executor通过ExecutorBackend来和Master的ScheduleEndpoint通信,相应的最常用的Endpoint是CoarseGrainedExecutorBackend。

(5)RDD

数据集,Spark定义了很多的数据集(RDD),比如HadoopRDD,JdbcRDD等。

RDD中的具体的数据有时是通过BlockManager来管理的,RDD中能寻址到数据所在的机器。

(6)Task

具体的任务,Master定义好Task后发布到集群中对应机器的Exector去执行,执行结果通过DirectResult和IndirectResult返回,后者通过包含了结果数据所在的Shuffle地址或者块地址等寻址信息。

(7)BlockManager

管理整个集群的Block,默认Block大小是128M,内存和磁盘数据的对应关系等也是通过相关的类来管理的。

以上是初步的比较笼统的一个框架结构,主要用于加强理解,要想更好的理解Spark必须要通过不断的读源码,后续时间笔者会依次和大家分享更具体的源码心得。

(8)MapOutTracker

跟踪整个集群的MapStatus,不同集群之间通过MapOutTrackerMaster等通信来同步信息。

 

2、DagSchedule任务调度

class DAGScheduler(
    private[scheduler] val sc: SparkContext,
    private[scheduler] val taskScheduler: TaskScheduler,
    listenerBus: LiveListenerBus,
    mapOutputTracker: MapOutputTrackerMaster,
    blockManagerMaster: BlockManagerMaster,
    env: SparkEnv,
    clock: Clock = new SystemClock())
  extends Logging

(1)Dag接受到的各种命令都通过Dag内部事件的方式被执行(而不是直接执行),便于Dag内部做一些排序调度的判断准备工作。

命令的种类:心跳、Exector的注册注销、Task的执行结束失败

(2)两种主要的stage:ResultStage,ShuffleMapStage

getShuffleMapStage:生成或者获得Shuffle类型的stage,同时要生成Shuffle的locs位置信息在里面

getParentStage:根据Rdd各依赖Rdd的Shuffle属性,获取所有Stage列表,这些Stage执行完成之后才能执行本Stage。

getMissingParentStages:获取所有缺失的父Stage,这里只判断Shuffle Stage的情况,ResultStage不考虑,如果缺失则生成该ShuffleToMapStage。

其他一系列维护Stage、Job关系的属性和方法。

(3)主要的Submit方式

SubmitJob:提交作业

生成该作业的finalStage,然后再生成ActiveJob,组装各状态HashMap,提交该finalStage

SubmitStage:提交某个Stage,与SubmitJob的区别是不生成新的ActiveJob。

submitMissingTasks:真正的提交Stage,当所有父Stage都准备就绪时执行,要重点看。stage的所有partitions生成多个Task。最后将这些tasks合并成TaskSet并提交到TaskSchedule(taskScheduler.submitTasks( new TaskSet(...))).

(4)TaskCompleted事件处理

广播事件到listenerBus;

找到Task所在的Stage:

a、如果是ResultTask,则更新该Stage属于的Job的状态,并判断Stage是否所有Task都执行完成,如果是则触发StageCompleted事件。好像也可能是JobCompleted事件,还要再看一次。

b、ShuffleMapTask,则找到对应的ShuffleStage,更新对应的Task所在分区的MapStatus(或者位置信息等),更新mapOutputTracker状态属性,最后启动所有满足提交状态的等待Stage(waitingStages)。

(5)handleExecutorAdded

当有额外的Executor加进来的时候,只是执行SubmitWaitingStage命令,这时候可能会有等待Stage满足了执行条件。

 

3、Task

ResultTask:直接在RDD上执行func

ShuffleMapTask:执行ShuffleDependcy的shuffleHandler方法,主要是一些聚合函数的计算,然后将对应的RDD分区数据执行这些聚合计算之后的结果写入到shuffleManager管理的writer中去,可能是写入到内存也可能写入到disk(猜测),shuffleManager一般会用到BlockManager来管理数据的存储。

Shuffle结果一般存储到集群的临时目录中,具体规则可参见DiskBlockManager和FileShuffleBlockResolver等类实现。

具体内容参见代码。

shuffleManager有这么几种:

(1)HashShuffleManager

(2)SortShuffleManager

当然也可以自定义

 

 

 

转载于:https://my.oschina.net/u/778683/blog/857038

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值