Spark 基本概念及 jobs stages tasks 等 解释

2019-09-23 11:23:09 浏览数 (1)

基础概念理解

  1. Application
代码语言:txt复制
用户在 spark 上构建的程序,包含了 driver 程序以及在集群上运行的程序代码,物理机器上涉及了 driver,master,worker 三个节点.
  1. Driver Program
代码语言:txt复制
创建 sc ,定义 udf 函数,定义一个 spark 应用程序所需要的三大步骤的逻辑:加载数据集,处理数据,结果展示。
  1. Cluster Manager
代码语言:txt复制
集群的资源管理器,在集群上获取资源的外部服务。 拿 Yarn 举例,客户端程序会向 Yarn 申请计算我这个任务需要多少的 memory,多少 CPU,etc。 然后 Cluster Manager 会通过调度告诉客户端可以使用,然后客户端就可以把程序送到每个 Worker Node 上面去执行了。
  1. Worker Node
代码语言:txt复制
集群中任何一个可以运行spark应用代码的节点。Worker Node就是物理节点,可以在上面启动Executor进程。
  1. Executor
代码语言:txt复制
在每个 Worker Node 上为某应用启动的一个进程,该进程负责运行任务,并且负责将数据存在内存或者磁盘上,每个任务都有各自独立的 Executor。 Executor 是一个执行 Task 的容器。它的主要职责是:
代码语言:txt复制
- 初始化程序要执行的上下文 SparkEnv,解决应用程序需要运行时的 jar 包的依赖,加载类。
- 同时还有一个 ExecutorBackend 向 cluster manager 汇报当前的任务状态,这一方面有点类似 hadoop的 tasktracker 和 task。
代码语言:txt复制
总结:Executor 是一个应用程序运行的监控和执行容器。
  1. Jobs
代码语言:txt复制
包含很多 task 的并行计算,可以认为是 Spark RDD 里面的 action,每个 action 的触发会生成一个job。 用户提交的 Job 会提交给 DAGScheduler,Job 会被分解成 Stage,Stage 会被细化成 Task,Task 简单的说就是在一个数据 partition 上的单个数据处理流程。
  1. Stage 一个 Job 会被拆分为多组 Task,每组任务被称为一个 Stage 就像 Map Stage, Reduce Stage。
  2. Task
代码语言:txt复制
被送到 executor 上的工作单元。 
代码语言:txt复制
> 在 Spark 中有两类 task:
>- shuffleMapTask
代码语言:txt复制
输出是shuffle所需数据, stage的划分也以此为依据,shuffle之前的所有变换是一个stage,shuffle之后的操作是另一个stage。
代码语言:txt复制
>- resultTask
代码语言:txt复制
输出是result,比如 rdd.parallize(1 to 10).foreach(println) 这个操作没有shuffle,直接就输出了,那么只有它的task是resultTask,stage也只有一个;
代码语言:txt复制
如果是rdd.map(x => (x, 1)).reduceByKey(_   _).foreach(println), 这个job因为有reduce,所以有一个shuffle过程,那么reduceByKey之前的是一个stage,执行shuffleMapTask,输出shuffle所需的数据,reduceByKey到最后是一个stage,直接就输出结果了。如果job中有多次shuffle,那么每个shuffle之前都是一个stage。
  1. Partition
代码语言:txt复制
Partition 类似 hadoop 的 Split,计算是以 partition 为单位进行的,当然 partition 的划分依据有很多,这是可以自己定义的,像 HDFS 文件,划分的方式就和 MapReduce 一样,以文件的 block 来划分不同的 partition。总而言之,Spark 的 partition 在概念上与 hadoop 中的 split 是相似的,提供了一种划分数据的方式。
代码语言:txt复制
> Block与Partition之间区别 
>- hdfs中的block是分布式存储的最小单元,类似于盛放文件的盒子,一个文件可能要占多个盒子,但一个盒子里的内容只可能来自同一份文件。假设block设置为128M,你的文件是250M,那么这份文件占3个block(128 128 2)。这样的设计虽然会有一部分磁盘空间的浪费,但是整齐的block大小,便于快速找到、读取对应的内容。(p.s. 考虑到hdfs冗余设计,默认三份拷贝,实际上3*3=9个block的物理空间。)
代码语言:txt复制
>- spark中的partition 是弹性分布式数据集RDD的最小单元,RDD是由分布在各个节点上的partition 组成的。partition 是指的spark在计算过程中,生成的数据在计算空间内最小单元,同一份数据(RDD)的partition 大小不一,数量不定,是根据application里的算子和最初读入的数据分块数量决定的,这也是为什么叫“弹性分布式”数据集的原因之一。总结:block位于存储空间、partition 位于计算空间,block的大小是固定的、partition 大小是不固定的,block是有冗余的、不会轻易丢失,partition(RDD)没有冗余设计、丢失之后重新计算得到
  1. RDD
代码语言:txt复制
每个RDD有5个主要的属性:
代码语言:txt复制
- 一组分片(partition),即数据集的基本组成单位
- 一个计算每个分片的函数
- 对parent RDD的依赖,这个依赖描述了RDD之间的lineage
- 对于key-value的RDD,一个Partitioner,这是可选择的
- 一个列表,存储存取每个partition的preferred位置。对于一个HDFS文件来说,存储每个partition所在的块的位置。这也是可选择的
代码语言:txt复制
把上面这5个主要的属性总结一下,可以得出RDD的大致概念。首先要知道,RDD大概是这样一种表示数据集的东西,它具有以上列出的一些属性。是spark项目组设计用来表示数据集的一种数据结构。而spark项目组为了让RDD能handle更多的问题,又规定RDD应该是只读的,分区记录的一种数据集合中。可以通过两种方式来创建RDD:一种是基于物理存储中的数据,比如说磁盘上的文件;另一种,也是大多数创建RDD的方式,即通过其他RDD来创建【以后叫做转换】而成。而正因为RDD满足了这么多特性,所以spark把RDD叫做Resilient Distributed Datasets,中文叫做弹性分布式数据集。
代码语言:txt复制
> 可以总下出几个它的特性来:
>
代码语言:txt复制
>- 不变的数据结构存储
代码语言:txt复制
>- 支持跨集群的分布式数据结构
代码语言:txt复制
>- 可以根据数据记录的key对结构进行分区
代码语言:txt复制
>- 提供了粗粒度的操作,且这些操作都支持分区
代码语言:txt复制
>- 它将数据存储在内存中,从而提供了低延迟性
  1. cores
代码语言:txt复制
每一个 core,相当于一个 worker 上的进程,这些进程会同时执行分配到这个 worker 上的任务。简单的说,就是 spark manager 把一个 job 切分几个 task 分发到 worker 上同步执行,而每个 worker 把分配给自己的 task 再切分成几个 subtask,分配给当前 worker 上的不同进程。
  1. Memory
代码语言:txt复制
分配给 spark 应用的内存有三个方面的应用:
代码语言:txt复制
 - spark 本身
 - spark 应用过程中 runtime 使用,比如 UDF 函数
 - spark 应用中的 cache
  1. narrow/wide dependences(宽依赖/窄依赖)
代码语言:txt复制
Spark中RDD的高效与DAG(有向无环图)有很大的关系,在DAG调度中需要对计算的过程划分Stage,划分的依据就是RDD之间的依赖关系。RDD之间的依赖关系分为两种,宽依赖(wide dependency/shuffle dependency)和窄依赖(narrow dependency)
代码语言:txt复制
> 1. 窄依赖
	窄依赖就是指父RDD的每个分区只被一个子RDD分区使用,子RDD分区通常只对应常数个父RDD分区,如下图所示【其中每个小方块代表一个RDD Partition】
代码语言:txt复制
窄依赖有分为两种:
代码语言:txt复制
一种是一对一的依赖,即OneToOneDependency

还有一个是范围的依赖,即RangeDependency,它仅仅被org.apache.spark.rdd.UnionRDD使用。UnionRDD是把多个RDD合成一个RDD,这些RDD是被拼接而成,即每个parent RDD的Partition的相对顺序不会变,只不过每个parent RDD在UnionRDD中的Partition的起始位置不同

代码语言:txt复制
> 2. 宽依赖
	宽依赖就是指父RDD的每个分区都有可能被多个子RDD分区使用,子RDD分区通常对应父RDD所有分区,如下图所示【其中每个小方块代表一个RDD Partition】
代码语言:txt复制
	![](https://img-blog.csdnimg.cn/20181105193150739.png)
  1. 本地内存与集群内存
代码语言:txt复制
本地内存,是指在 driver 端的程序所需要的内存,由 driver 机器提供,一般用来生成测试数据,接受运算结果等; 

集群内存,是指提交到集群的作业能够向集群申请的最多内存使用量,一般用来存储关键数据

  1. shuffle shuffle 是两个 stage 之间的数据传输过程。

RDD内在 与 Spark Stage

当使用流式数据源例如 Kafka 时,它会根据所读取的 Topic 中的 Partition 数量来建立 RDD 中的 Partition,一一对应,这样就能并行读取源数据,理论上 Kafka 的 Partition 越多,并发程度越好。

对于 RDD 的 Partition 数量, 使用 Spark Streaming 的 Kafka 套件来说,是与 Kafka 的 Partition 相同,对于普通 RDD 而言,如初始化时无指定 Partition 数量,默认是资源 CPU 个数。可以通过 Spark UI 查看 Task 数量确定

Spark 中,Partition 的数量很大程度上影响 Spark 调度,执行一个任务的效率,且 Partition 的数量并非一尘不变,根据你所提交的操作,会动态的改变新生成 RDD 中的 Partition 数量。 这类操作被分为大致两类 宽依赖,窄依赖

RDD 在各种操作中会不断生成新的 RDD,其中的 Partition 可能随之而变。

  • 例如 map,flatMap 即窄依赖,不会改变 Partition数量,新 RDD 和 旧 RDD 的 Partition 是一致的
  • reduceByKey 即宽依赖,会改变 Partition 的数量
  • Partition 数量的改变就是 Spark 划分不同 Stage 的标志

Stage是 Spark 任务调度的阶段划分概念,只有先执行完前面的 Stage,后面的 Stage 才能被执行。

每个 Stage 中按照 Partition 生成一个 task,所有 task 组成 taskset 放进 任务调度其中去调度执行

整个过程叫做 DAG调度

DAG调度 在 Spark 中主要依赖于 Spark 接收到一个任务后对整条关系链的划分

代码语言:txt复制
# ----------     map, faltMap      ---------- #
代码语言:txt复制
# | Part-1 |  -------------------> | Part-5 | #
代码语言:txt复制
# | Part-2 |  -------------------> | Part-6 | #
代码语言:txt复制
# | Part-3 |  -------------------> | Part-7 | #
代码语言:txt复制
# | Part-4 |  -------------------> | Part-8 | #
代码语言:txt复制
# ----------         窄依赖         ---------- #
代码语言:txt复制
# Stage 1                                     #

Reference

  1. http://litaotao.github.io/spark-questions-concepts?s=inner
  2. https://www.jianshu.com/p/5c2301dfa360

0 人点赞