spark核心组件的介绍

Posted 张小小凡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spark核心组件的介绍相关的知识,希望对你有一定的参考价值。

1-Spark核心组件

1.1Driver

Spark 驱动器节点,用于执行 Spark 任务中的 main 方法,负责实际代码的执行工作。Driver 在 Spark 作业执行时主要负责:

  • 将用户程序转化为作业job
  • 在executor之间调度任务
  • 跟踪executor的执行情况
  • 通过UI展示查询运行情况

1.2Executor

Spark Executor 对象是负责在 Spark 作业中运行具体任务,任务彼此之间相互独立。

两个核心功能:

  • 负责运行组成 Spark 应用的任务,并将结果返回给驱动器(Driver)
  • 它们通过自身的块管理器(Block Manager)为用户程序中要求缓存的 RDD 提供内存 式存储。RDD 是直接缓存在 Executor 进程内的,因此任务可以在运行时充分利用缓存 数据加速运算。

2-Spark部署模式

多种部署模式,有standalone,Hadoop Yarn,Mesos,K8S等。但是我们工作中主要用的是yarn-cluster部署模式。

yarn-cluster部署模式任务的提交流程:

  1. 执行脚本提交任务,实际是启动一个 SparkSubmit 的 JVM 进程;
  2. SparkSubmit 类中的 main 方法反射调用 YarnClusterApplication 的 main 方法;
  3. YarnClusterApplication 创建 Yarn 客户端,然后向 Yarn 服务器发送执行指令:bin/java ApplicationMaster;
  4. Yarn 框架收到指令后会在指定的 NM 中启动 ApplicationMaster;
  5. ApplicationMaster 启动 Driver 线程,执行用户的作业;
  6. AM 向 RM 注册,申请资源;
  7. 获取资源后 AM 向 NM 发送指令:bin/java YarnCoarseGrainedExecutorBackend;
  8. CoarseGrainedExecutorBackend 进程会接收消息,跟 Driver 通信,注册已经启动的 Executor;然后启动计算对象 Executor 等待接收任务
  9. Driver 线程继续执行完成作业的调度和任务的执行。
  10. Driver 分配任务并监控任务的执行。

3-Spark任务调度机制

Driver 线程 主 要 是 初 始 化 SparkContext 对 象 , 准 备 运 行 所 需 的 上 下 文 , 然 后 一 方 面 保 持 与 ApplicationMaster 的 RPC 连接,通过 ApplicationMaster 申请资源,另一方面根据用户业务 逻辑开始调度任务,将任务下发到已有的空闲 Executor 上。

当 ResourceManager 向 ApplicationMaster 返回 Container 资源时,ApplicationMaster 就尝 试在对应的 Container 上启动 Executor 进程,Executor 进程起来后,会向 Driver 反向注册, 注册成功后保持与 Driver 的心跳,同时等待 Driver 分发任务,当分发的任务执行完毕后, 将任务状态上报给 Driver。

Driver启动后会初始化几个对象分别是:

  • DAGScheduler
  • TaskScheduler
  • SchedulerBackend
  • HeartbeatReceiver

3.1 DAGScheduler

通过spark submit的任务,不管是纯RDD的计算还是sparkSQL还是spark streaming,他们最后都会解析成RDD的计算。RDD是有血缘关系的,可以根据这个血缘关系生成DAG有向无环图。

DAGScheduler根据这个图进行stage的切分。由于RDD的计算是懒加载的,当遇见action算子的时候会触发计算。根据DAG从后向前每遇到一个产生shuffle的算子即宽依赖就切分一个stage。所以一个job的stage的数量是shfull算子数量+1。

只有当父stage执行完后,才会执行下一个stage。stage提交时会将将task信息(分区及计算逻辑)打包成TaskSet交给TaskScheduler。一个partition对应一个task。taskcheduler会监控stage的状态,当Executor丢失或者Task 由于 Fetch 失败,需要重新提交失败的stage。

同一个stage中的计算可以pipeline式的计算。如图

3.2 TaskScheduler

TaskScheduler主要负责Task的调度,由DAGScheduler把TaskSet发到TaskScheduler后,TaskScheduler会将TaskSet封装为TaskSetManager加入到调度队列中。结构如图:

这里的调度队列分为FIFO和FAIR。

TaskSetManager 负 责监控 管理 同一 个 Stage 中的 Tasks, TaskScheduler 就是以 TaskSetManager 为单元来调度任务。

3.3 SchedulerBackend

SchedulerBackend,它负责跟外界打交道, 接收 Executor 的注册信息,并维护 Executor 的状态,所以说 SchedulerBackend 会定期地去“询问”TaskScheduler 有没有任务要运行,TaskScheduler 在 SchedulerBackend“问” 它的时候,会从调度队列中按照指定的调度策略选择 TaskSetManager 去调度运行。

3.4 HeartbeatReceiver

Executor启动后注册到SchedulerBackend上,并始终通过HeartbeatReceiver与SchedulerBackend维持一个心跳。根据心跳的情况来判断这个executor是否存活,在注册的executor列表中把掉的executor去掉。

在executor执行任务的时候,由于数据量很大,产生GC时,会停止发送心跳。这时如果把这个executor提出资源列表,也代表这个task失败,会重新分配。可以根据情况适当增大心跳间隔时间,来避免这种情况的发生。

3.5 本地化调度

DAGScheduler 切割 Job,划分 Stage, 通过调用 submitStage 来提交一个 Stage 对应的 tasks,submitStage 会调用submitMissingTasks,submitMissingTasks 确定每个需要计算的 task 的 preferredLocations。

也就是说我有很多executor在不同的container上,这些container在不同的节点上。那这个task到底交给哪个executor来执行呢?一共有5个分配策略。因为我们的数据是分布式的存在多个节点上,那么把task交给数据和executor在同一个节点来运行就是最优的。

名称 解析
PROCESS_LOCAL 进程本地化,task 和数据在同一个 Executor 中,性能最好。
NODE_LOCAL 节点本地化,task 和数据在同一个节点中,但是 task 和数据不 在同一个 Executor 中,数据需要在进程间进行传输。
RACK_LOCAL 机架本地化,task 和数据在同一个机架的两个节点上,数据需要 通过网络在节点之间进行传输。
NO_PREF 对于 task 来说,从哪里获取都一样,没有好坏之分。
ANY task 和数据可以在集群的任何地方,而且不在一个机架中,性能 最差。

在调度执行时,Spark 调度总是会尽量让每个 task 以最高的本地性级别来启动,当一个 task 以 X 本地性级别启动,但是该本地性级别对应的所有节点都没有空闲资源而启动失败, 此时并不会马上降低本地性级别启动而是在某个时间长度内再次以 X 本地性级别来启动该 task,若超过限时时间则降级启动,去尝试下一个本地性级别,依次类推。可以通过调大每个类别的最大容忍延迟时间,在等待阶段对应的 Executor 可能就会有 相应的资源去执行此 task,这就在在一定程度上提到了运行性能。

3.6 失败重试与黑名单机制

除了选择合适的 Task 调度运行外,还需要监控 Task 的执行状态,前面也提到,与外部 打交道的是 SchedulerBackend,Task 被提交到 Executor 启动执行后,Executor 会将执行状态 上报给 SchedulerBackend,SchedulerBackend 则告诉 TaskScheduler,TaskScheduler 找到该 Task 对应的 TaskSetManager,并通知到该 TaskSetManager,这样 TaskSetManager 就知道 Task 的失败与成功状态,对于失败的 Task,会记录它失败的次数,如果失败次数还没有超过最大 重试次数,那么就把它放回待调度的 Task 池子中,否则整个 Application 失败。

在记录 Task 失败次数过程中,会记录它上一次失败所在的 Executor Id 和 Host,这样下 次再调度这个 Task 时,会使用黑名单机制,避免它被调度到上一次失败的节点上,起到一 定的容错作用。黑名单记录 Task 上一次失败所在的 Executor Id 和 Host,以及其对应的“拉 黑”时间,“拉黑”时间是指这段时间内不要再往这个节点上调度这个 Task 了。

最后附上一张任务提交流程图

下期讲spark的shuffle也是面试的重点


以上是关于spark核心组件的介绍的主要内容,如果未能解决你的问题,请参考以下文章

Spark1——介绍

Spark中经常使用工具类Utils的简明介绍

Spark内核解析

Spark认识及性能调优

Spark 核心组件解析

Spark系列