Spark 概述
运行速度快
容易使用
Spark本质上计算模式也是MapReduce,但是操作不局限于Map和Reduce两个操作,提供了更多的操作类型。而且Spark会存储在内存中,磁盘IO开销很小。
Spark 生态系统
大数据处理主要包括:
- 复杂的批量数据处理
- 基于历史数据的交互式查询
- 基于实时数据流的数据处理
过去我们需要同时部署三种不同的软件,如MapReduce、Impala、Storm
会存在如下问题:
- 不同场景之间输入输出数据无法做到无缝共享,通常需要进行数据格式的转换。
- 不同的软件需要不同的开发和维护团队,带来了较高的使用成本。
- 比较难以对同一个集群中的各个系统进行统一的资源协调和分配。
而Spark是一套完整的生态系统。可以部署在资源管理器YARN上,提供一站式大数据解决方案。
已经成为伯克利数据分析软件栈BDAS的重要组成部分。
综上,Spark就是牛逼!
Spark 运行架构
基本概念
- RDD:是Resillient Distributed Dataset(弹性【可多可少,分区数量可变】分布式数据集)的简称,是分布式内存的一个抽象概念,提供了一种高度受限的共享内存模型。Spark编程核心抽象(重要!!!)。
- DAG:是Directed Acyclic Graph(有向无环图)的简称,反映RDD之间的依赖关系。
- Executor:是运行在工作节点(WorkerNode)的一个进程,负责运行Task。
- 应用(Application):用户编写的Spark应用程序。
- 任务( Task ):运行在Executor上的工作单元
- 作业( Job ):一个作业包含多个RDD及作用于相应RDD上的各种操作
- 阶段( Stage ):是作业的基本调度单位,一个作业会分为多组任务,每组任务被称为阶段,或者也被称为任务集合,代表了一组关联的、相互之间没有Shuffle依赖关系的任务组成的任务集。
Spark 运行架构如下图所示:
这是一种主从架构,一个主节点加上多个从节点。主节点是Driver Program,从节点为Worker Node。
其中Cluster Manager是一种集群资源管理器。
Spark中各种概念之间的相互关系如下:
一个应用由一个Driver和若干个作业构成,一个作业由多个阶段构成,一个阶段由多个没有Shuffle关系的任务组成
Spark 运行基本流程
(1)首先为应用构建起基本的运行环境,即由Driver创建一个SparkContext(总指挥官),进行资源的申请、任务的分配和监控。
(2)资源管理器为Executor分配资源,并启动Executor进程。
(3)SparkContext根据RDD的依赖关系构建 DAG 图,DAG图提交给DAGScheduler 解析成 Stage,然后把一个个 TaskSet 提交给底层调度器 TaskScheduler 处理;Executor SparkContext 申请Task,Task Scheduler将 Task发放给 Executor 运行,并提供应用程序代码。(计算向数据靠拢原则)。
(4)Task在Executor上运行,把执行结果反馈给TaskScheduler,然后反馈给 DAGScheduler,运行完毕后写 SparkContext 入数据并释放所有资源。
RDD 运行原理
设计背景
迭代式计算,中检结果重用。导致磁盘IO开销和序列化和反序列化开销。RDD就是为了满足这种迭代式计算需求而出现的。它提供了一个抽象数据结构,我们不必担心底层数据的分布式特性,只需将具体的应用逻辑表达为一系列转换处理,不同RDD之间的转换操作形成依赖关系,即DAG图。
RDD 概念
一个RDD就是一个分布式对象集合,本质上是一个只读的分区记录集合。它是一种高度受限(只读,不能直接修改),只能基于稳定的物理存储中的数据集创建RDD,或者通过在其他RDD上执行确定的转换操作(如map、join和group by)而创建得到新的RDD。
RDD提供了一组丰富的操作,但是这组操作只支持粗粒度修改,一次只针对RDD全集进行转换。
- “动作” (Action)
- “转换” (Transformation)
不支持细粒度修改,比如不适合网页爬虫。但是RDD其实是非常强大的,可以满足企业各种需求。Spark提供了RDD的API,可以通过调用API实现对RDD的各种操作。
RDD的典型执行过程:
- RDD读入外部数据源进行创建
- RDD经过一系列的转换(Transformation)操作,每一次都会产生不同的RDD,供给下一个转换操作使用
- 最后一个RDD经过**“动作”操作进行转换,并输出到外部数据源**
惰性调用机制:
一系列的转换只是记录转换的轨迹意图,不做计算,只有遇到第一个动作才会触发从头到尾的计算。
管道化:
避免不必要的磁盘IO
每次操作简单:
虽然每次操作简单,但是这些操作结合起来就会产生复杂的操作,实现复杂的功能。
RDD的特性:
- 高效的容错性
- RDD:血缘关系、重新计算丢失分区、无需回滚系统、重算过程在不同节点之间并行、只记录粗粒度的操作。比如F丢了,可以从E开始生成。
- 中间结果持久化到内存,避免磁盘IO开销。
- 存到的数据可以是Java对象,避免了不必要的对象序列化和反序列化。
RDD之间的依赖关系
- Shuffle操作
如下图,(“a”,1)都到reduce1中,相当于“洗牌” - 窄依赖和宽依赖
发生了Shuffle操作是宽依赖,否则是窄依赖。
窄依赖:
一个父亲对应一个儿子
多个父亲对应一个儿子 - 宽依赖:
一个父亲对应多个儿子
阶段的划分
进行分阶段时,阶段划分的依据就是看宽依赖还是窄依赖。
因为窄依赖可进行流水线优化,而宽依赖包含Shuffle过程,一定会写磁盘。无法实现流水线方式处理。
fork/join 机制
一次转换就是一个fork/join,多次就是多个fork/join过程。
举个例子:
这里一共要花6个小时,其实可以优化成如下过程:
上面的例子是窄依赖,下面举个宽依赖的例子。
这里不得不在上海落地,进行shuffle,所以无法优化。所以遇到宽依赖就得切开阶段,生成不同的阶段,遇到窄依赖就可以直接流水线,不断加入阶段。
RDD 运行过程
(1)创建RDD对象;
(2)SparkContext负责计算RDD之间的依赖关系,构建DAG;
(3)DAGScheduler负责把DAG图分解成多个Stage,每个Stage中包含了多个Task,每个Task会被TaskScheduler分发给各个WorkerNode上的Executor去执行。
Spark的部署方式
- Standalone:Spark自带,性能不高
- Mesos:性能最高
- YARN:用的最多,通用调度管理。
Spark会取代MapReduce,而不能说是否会取代Hadoop,Hadoop还包括HDFS,HBase。