Spark简单原理

Application:我们自己的 Spark 程序。

TaskRunner:将我们编写的代码,也就是要执行的算子以及函数拷贝,反序列化,然后执行 task。

Task:task 有两种 ShuffleMapTask 和 ResultTask,只有最后一个 Stage 是 ResultTask,其余是 ShuffleMapTask。

1.submit 提交,在当前节点启动一个 Driver 进程

2 . Driver执行Application(Application总是先创建SparkContext)构造SparkContext在初始化的时候做的最重要的两件事情就是构建DAGScheduler和TaskScheduler

3.在构造出 TaskScheduler 的时候,TaskScheduler 会你负责连接 Master,并向Master 注册 Application。
4.Master 通知 Worker 启动 Executor;Master 接收到 Application 注册的请求后会使用自己的资源调度算在 Spark 集群的 Worker 上让 Worker 为这个 Application启动多个 Executor。(调度算法)

5. Executor 启动之后会反向注册到 TaskScheduler 上。当所有 Executor 都注册到Driver 上Driver 的 SparkContext 初始化结束,会继续执行我们的代码。

6.每执行到一个 Action 操作就会创建一个 job;并把 job 提交给 DAGScheduler。

7.DAGScheduler 会将 job 划分为多个 stage,然后每个 stage 创建一个 TaskSet(里面包含了很多 task)。并把每一个 Taskset 给 TaskScheduler。(stage 划分算法)

8.TaskScheduler 会把 TaskSet 里的每一个 Task 提交到 Executor 上运行(task 分配算法)

扫描二维码关注公众号,回复: 4230804 查看本文章

9.Executor 每收到一个 Task 都会用一个 TaskRunner 来封装 task,然后从线程池里取出一个线程来执行 task。所以最后整个 Spark 应用程序的执行及时 Stage 分批次作为 TaskSet 提交到Executor 执行。每个 Task 针对 RDD 的一个 partition 执行我们定义的算子和函数。

Master

1.主备切换机制

2.注册机制

    Worker 的注册:
    第一步 Worker 启动之后就会主动向 Master 进行注册

    第二步过滤,将状态是 dead 的 Worker 过滤掉,对于状态为 unknown 的Worker,清理旧的 Worker 信息替换为新的 Worker 信息

    第三步把 Worker 加入内存缓存中(HashMap)

    第四步用持久化引擎将 Worker 信息进行持久化

    第五步调用 scheduler()方法进行调度

    Driver 的注册:
    第一步用 Spark-submit 提交 Application 时首先就会注册 Driver

    第二步把 Driver 信息加入内存缓存中(HashMap)

    第三步加入等待调度队列(ArrayBuffer)

    第四步用持久化引擎将 Worker 信息进行持久化

    第五步调用 scheduler()方法进行调度

Application 的注册(很重要):

    第一步 Driver 启动好之后会执行我们的 Application 代码,初始化SparkContext,底层的 SparkDeploySchedulerBackend 会向 Master 注册

    第二步把 Application 信息加入内存缓存中(HashMap)

    第三步加入等待调度 Application 队列(ArrayBuffer)

    第四步用持久化引擎将 Application 信息进行持久化

    第五步调用 scheduler()方法进行调度

3、状态改变处理机制源码分析

4、资源调度机制源码分析(schedule(),两种资源调度算法)

Application 的调度

    spreadOutApps:每个可用 Worker 均分
    非 spreadOutApps:尽可能少的 Worker 数量

DAGScheduler

    Stage 划分算法:

    从触发 Action 操作的那个 rdd 往前倒推,首先为最后一个 rdd 创建一个 stage,然后往前倒推,如果发现某个 rdd 是宽依赖,那么就会将宽依赖的那个 rdd 划分为一个新的 stage,然后以此类推,直到所有 rdd 遍历完为止。源代码归结为以下三部:

  1. 从 finalStage 倒推

  2. 通过宽依赖来进行新的 Stage 的划分

  3. 使用递归优先提交父 Stage

对于每一种有 shuffle 的操作,比如:groupByKey、reduceByKey、countByKey底层都对应了三个 RDD:MapPartitionsRDD、ShuffleRDD、MapPartitionsRDD,第一对应一个 Stage,后两个对应一个 Stage

    Task 的最佳位置

    Stage 从最后一个 RDD 开始找,哪个 RDD 的 Partition 被 cache 或者 checkpoint了,那么 task 的最佳位置就是 cache 或者 checkpoint 的位置。好处:这样 task在该节点执行,直接找缓存或者 checkpoint 的数据,不用再计算之前的 RDD 了。找完所有的 RDD 如果都没有缓存或者 checkpoint,那么久没有最佳位置,那么此task 就要遵循 TaskScheduler 的分配。

TaskScheduler

    给每个 TaskSet 都会创建一个 TaskSetManager,TaskSetManager 会负责他的那个 TaskSet 的运行状况的监视和管理。

    Task 的分配:Spark 用本地化级别这种模型去优化 Task 的分配和启动,优先希望在最佳本地化的地方启动 Task

    PROCESS_LOCAL:进程本地化,代码和数据在同一个进程中,也就是在同一个 executor 中;计算数据的 task 由 executor 执行,数据在 executor 的 BlockManager中;性能最好NODE_LOCAL:节点本地化,代码和数据在同一个节点中;比如说,数据作为一个 HDFS block 块,就在节点上,而 task 在节点上某个 executor 中运行;或者是,数据和 task 在一个节点上的不同 executor 中;数据需要在进程间进行传输

    NO_PREF:对于 task 来说,数据从哪里获取都一样,没有好坏之分

    RACK_LOCAL:机架本地化,数据和 task 在一个机架的两个节点上;数据需要通过网络在节点之间进行传输

    ​ANY:数据和 task 可能在集群中的任何地方,而且不在一个机架中,性能最差

猜你喜欢

转载自my.oschina.net/u/4009325/blog/2397374