Spark基本概念

Spark基本概念

  1. Application

用户在 spark 上构建的程序,包含了 driver 程序以及在集群上运行的程序代码,物理机器上涉及了 driver,master,worker 三个节点.

  1. Driver Program

创建 sc ,定义 udf 函数,定义一个 spark 应用程序所需要的三大步骤的逻辑:加载数据集,处理数据,结果展示。

  1. Cluster Manager (Yarn, Mesos,Standlone)

集群的资源管理器,在集群上获取资源的外部服务。 拿 Yarn 举例,客户端程序会向 Yarn 申请计算我这个任务需要多少的 memory,多少 CPU,etc。 然后 Cluster Manager 会通过调度告诉客户端可以使用,然后客户端就可以把程序送到每个 Worker Node 上面去执行了。

  1. Worker Node

集群中任何一个可以运行spark应用代码的节点。Worker Node就是物理节点,可以在上面启动Executor进程。

  1. Executor

在每个 Worker Node 上为某应用启动的一个进程,该进程负责运行任务,并且负责将数据存在内存或者磁盘上,每个任务都有各自独立的 Executor。 Executor 是一个应用程序运行的监控和执行容器。它的主要职责是:初始化程序要执行的上下文 SparkEnv,解决应用程序需要运行时的 jar 包的依赖,加载类。

  1. Job

包含很多 task 的并行计算,可以认为是 Spark RDD 里面的 action,每个 action 的触发会生成一个job。 用户提交的 Job 会提交给 DAGScheduler,Job 会被分解成 Stage,Stage 会被细化成 Task,Task 简单的说就是在一个数据 partition 上的单个数据处理流程。

  1. Stage

一个 Job 会被拆分为多组 Task,每组任务被称为一个 Stage。

两个 stage 之间的数据传输过程称为shuffle。

Stage 的划分在 RDD 的论文中有详细的介绍,简单的说是以 shuffle 和 result 这两种类型来划分。 在 Spark 中有两类 task:

  • shuffleMapTask:
    输出是shuffle所需数据, stage的划分也以此为依据,shuffle之前的所有变换是一个stage,shuffle之后的操作是另一个stage。
  • resultTask:
    输出是result.

比如 rdd.parallize(1 to 10).foreach(println) 这个操作没有shuffle,直接就输出了,那么只有它的task是resultTask,stage也只有一个;如果是rdd.map(x => (x, 1)).reduceByKey(_ + _).foreach(println), 这个job因为有reduce,所以有一个shuffle过程,那么reduceByKey之前的是一个stage,执行shuffleMapTask,输出shuffle所需的数据,reduceByKey到最后是一个stage,直接就输出结果了。如果job中有多次shuffle,那么每个shuffle之前都是一个stage。

  1. Task

被送到 executor 上的工作单元。

  1. Partition

一个 task 的计算单位。

  1. RDD

每个RDD有5个主要的属性:

  • 一组分片(partition),即数据集的基本组成单位
  • 一个计算每个分片的函数
  • 对parent RDD的依赖,这个依赖描述了RDD之间的lineage
  • 对于key-value的RDD,一个Partitioner,这是可选择的
  • 一个列表,存储存取每个partition的preferred位置。对于一个HDFS文件来说,存储每个partition所在的块的位置。这也是可选择的

把上面这5个主要的属性总结一下,可以得出RDD的大致概念:

首先要知道,RDD大概是这样一种表示数据集的东西,它具有以上列出的一些属性。是spark项目组设计用来表示数据集的一种数据结构。而spark项目组为了让RDD能handle更多的问题,又规定RDD应该是只读的,分区记录的一种数据集合中。可以通过两种方式来创建RDD:一种是基于物理存储中的数据,比如说磁盘上的文件;另一种,也是大多数创建RDD的方式,即通过其他RDD来创建【以后叫做转换】而成。而正因为RDD满足了这么多特性,所以spark把RDD叫做Resilient Distributed Datasets,中文叫做弹性分布式数据集。很多文章都是先讲RDD的定义,概念,再来说RDD的特性。我觉得其实也可以倒过来,通过RDD的特性反过来理解RDD的定义和概念,通过这种由果溯因的方式来理解RDD也未尝不可。反正对我个人而言这种方式是挺好的。

RDD是Spark的核心,也是整个Spark的架构基础,可以总下出几个它的特性来:

  • 它是不变的数据结构存储
  • 它是支持跨集群的分布式数据结构
  • 可以根据数据记录的key对结构进行分区
  • 提供了粗粒度的操作,且这些操作都支持分区
  • 它将数据存储在内存中,从而提供了低延迟性
  1. sc.parallelize

parallelize(c, numSlices=None)

简单的说,parallelize 就是把 driver 端定义的一个数据集,或者一个获取数据集的生成器,分发到 worker 上的 executor 中,以供后续分析。这种方式在测试代码逻辑时经常用到,但在构建真正的 spark 应用程序时很少会用到,一般都是从 hdfs 或者数据库去读取数据。

  1. code distribute

提交 spark 应用时,spark 会把应用代码分发到所有的 worker 上面,应用依赖的包需要在所有的worker上都存在.

  1. Core

每一个 core,相当于一个 worker 上的进程,这些进程会同时执行分配到这个 worker 上的任务。简单的说,就是 spark manager 把一个 job 切分几个 task 分发到 worker 上同步执行,而每个 worker 把分配给自己的 task 再切分成几个 subtask,分配给当前 worker 上的不同进程。

  1. Memory

分配给 spark 应用的内存有三个方面的应用:

  • spark 本身
  • spark 应用
  • spark 应用过程中 runtime 使用,比如 UDF 函数
  • spark 应用中的 cache
  1. RDD narrow/wide dependences
  • 窄依赖是指子RDD的每个分区依赖于常数个父分区(即与数据规模无关)。

  • 宽依赖指子RDD的每个分区依赖于所有父RDD分区。

  • 计算方面:

    • 计算窄依赖的子RDD:可以在某一个计算节点上直接通过父RDD的某几块数据(通常是一块)计算得到子RDD某一块的数据;
    • 计算宽依赖的子RDD:子RDD某一块数据的计算必须等到它的父RDD所有数据都计算完成之后才可以进行,而且需要对父RDD的计算结果进行hash并传递到对应的节点之上;
  • 容错恢复方面:

    • 窄依赖:当父RDD的某分片丢失时,只有丢失的那一块数据需要被重新计算;
    • 宽依赖:当父RDD的某分片丢失时,需要把父RDD的所有分区数据重新计算一次,计算量明显比窄依赖情况下大很多;

你可能感兴趣的