大数据实验课复习提纲(四)——Spark

1. 为什么需要Spark?

  • MapReduce可以高效执行批处理任务,但无法应对实时计算的需求
  • MapReduce缺乏Job间的数据共享原语,但通过HDFS共享是低效的
  • MapReduce提出的时代,内存稀缺,因此没有考虑充分利用内存计算,目前看来这是性能低下的
  • MapReduce对于复杂计算表现力差

2. Spark的优点

  • 高速:内存计算比MR快100倍
  • 易用性:可在多种编程语言平台上使用
  • 广泛性:综合了SQL、流式计算和复杂分析等多种领域
  • 多处运行:可以在很多平台上运行,数据来源亦十分广泛

Spark还提出了弹性分布式数据集(RDD)。由于再大的内存也很难放下计算需要的所有数据,这一数据集可以存放在内存中,也可以在磁盘中,这便是“弹性”的含义。Spark通过对RDD操作来完成计算。

3. Spark基本构架和组件

Spark上层有包括SQL、Streaming等多种工具,反映广泛性;底层可由YARN、Mesos或直接在本地运行等,反映多处运行

Spark系统的基本结构是,一个Master节点,多个Worker节点,和MapReduce如出一辙。此外Worker节点下有Executor,负责完成Task程序的执行。不知道这样的设计是不是和YARN保持了一致。

为了知道Spark怎么运作,我们还需要知道Spark应用程序的基本结构。这一程序横跨整个系统,但整体上而言,是由一个Driver Program和多个Executor构成的。程序可能会执行多个Job,每个Job又包含多个Stage,每个Stage由多个Task组成,这是程序的基本执行单元,在Executor上执行。(说了这么多背书的东西,还不如直接去看源码好。)

3.1. Driver

Driver创建SparkContext,它包含了可执行的RDD有向无环图,并构建基于Stage的有向无环图。TaskScheduler解析这些信息,并发起调度,将Task分发给Executor执行。

3.2. Worker

CoarseGrainedExecutorBackend进程包含Executor对象,它持有一个线程池,里面有很多Task,不同线程可共享内存资源。一个Worker只能有一个Executor,一一对应,然而一个Worker node下可以有多个Worker。

3.3. Spark程序运行机制

  • Client提交应用,Master节点启动Driver。
  • Driver向Cluster Manager申请资源,并启动SparkContext。这里的Cluster Manager就像YARN中的Resource Manager一样,而Driver则是ApplicationMaster。
  • SparkContext向Cluster Manager申请Executor资源,并启动CoarseGrainedExecutorBackend作为Executor。
  • Executor向SparkContext申请Task,并获得执行的代码。

总而言之,在集群模式下运行,它的大体步骤就是由YARN来限定的。如果还不清楚YARN是什么,没关系,这篇文章综合了YARN和MapReduce,可以解答你的疑惑。

任务是以这样的方式来体现的:

这是RDD的有向无环图,RDD在map、filter等映射的作用下不断变化,最终产生计算结果。每个RDD由多个Partition组成,这是Task作用的基本单位。

如刚才所述,这是Stage的有向无环图。Stage作用的单位是RDD,Task作用的单位是Partition,读者应能体会到这种分层关系。

所以有了DAG,我们就有机会找出DAG中存在并行的部分,并将其调度到不同的Executor上执行。

4. Spark程序模型

RDD支持两种类型操作:

  • 转换(transformation):它定义了新的RDD,但并不立即计算其中的值。例如filter操作,这和python中的filter一致,是惰性的。
  • 动作(action):立即计算RDD,并返回结果给程序,或写入外存储。例如计算count。

RDD有两种容错方式:

  • Lineage:RDD可以只记录变换,但不存储实际数据,即可完成数据恢复
  • CheckPoint:若lineage太长,这一恢复过程也较慢,因此设置CheckPoint就是最稳妥的选择

RDD之间的依赖关系:

  • 窄依赖:父RDD的一个Partition最多被子RDD的一个Partition所依赖
  • 宽依赖:父RDD的一个Partition被子RDD的多个Partition所依赖

窄依赖对优化更有利。一方面,父RDD分区只把数据发送给一个子RDD分区即可;另一方面,如果子RDD分区寄了,父RDD重新计算不会带来冗余。看下面的宽依赖,b1损坏之后,a1、a2、a3都会重算,那么对于b2来说这是一种冗余。

RDD持久化的存储策略包括:

  • 未序列化的Java对象,存储于内存中。它的性能最好,可以直接访问内存中的RDD对象。
  • 序列化数据,存储与内存中。它便于内存存储,但代价是需要反序列化才能使用。
  • 磁盘存储。它适用于RDD太大时的情形,但是重新计算RDD会带来巨大的开销。

发表评论

您的电子邮箱地址不会被公开。