spark 特点
spark是基于内存计算的大数据并行计算框架
具有如下特点:
运行速度快
Spark使用先进的DAG 执行引擎,基于内存的执行速度可比Hadoop MapReduce快上百倍,基于磁盘的执行速度也能快十倍容易使用
支持使用Scala、Java、Python和R语言进行编通用性
Spark提供了完整而强大的技术栈,包括SQL查询、流式计算、机器学习和图算法组件运行模式多样
Spark可运行于独立的集群模式中,或者运行于Hadoop中,
且可以访问 HDFS、HBase、Hive等多种数据源
相对于Hadoop的优势
Hadoop的一些缺点:
表达能力有限:
计算都必须要转化成 Map 和 Reduce两个操作,难以描述复杂的数据处理过程磁盘IO开销大:
每次执行时都需要从磁盘读取数据,并且在计算完成后需要将中间结果写入到磁盘中延迟高:
一次计算可能要分解成多个 MapReduce 任务,任务衔接涉及IO开销,延迟高
Spark的优点:
表达能力更灵活:
Spark计算模式也属于MapReduce,但不局限于此,还提供了多种操作类型IO开销小,速度更快:
提供了内存计算,中间结果直接放到内存中,带来了更高的迭代运算效率,
更适合迭代运算较多的数据挖掘和机器学习更优的运行机制:
基于DAG的任务调度执行机制,要优于MapReduce的迭代执行机制。编程更方便:
相对于Hadoop需要编写不少相对底层代码,Spark提供多种高层次、简介的API
相同的功能,代码量比Hadoop少2~5倍。并提供实时交互式编程反馈(后面关注一下)
Spark有很多优势,并不能完全替代Hadoop,主要用于替代Hadoop中的MapReduce。
Spark已经很好地融入了Hadoop生态圈,并成为其中的重要一员。
借助于YARN实现资源调度,借助于HDFS实现分布式存储。
不过 Spark对硬件的要求稍高,对内存和CPU有一定的要求。
Spark 生态系统
主要包含了Spark Core、Spark SQL、Spark Streaming、MLLib和GraphX 等组件
Spark Core:
Spark Core包含Spark的基本功能,如内存计算、任务调度、部署模式、存储管理等
通常所说的Apache Spark,就是指Spark Core;Spark SQL:
Spark SQL允许开发人员直接处理RDD,同时也可查询Hive、HBase等外部数据源。
Spark SQL的一个重要特点是其能够统一处理关系表和RDD,
使得开发人员可以轻松地使用SQL命令进行查询,并进行更复杂的数据分析;Spark Streaming:
Spark Streaming支持高吞吐量、可容错处理的实时流数据处理,
其核心思路是将流式计算分解成一系列短小的批处理作业。
Spark Streaming支持多种数据输入源,如Kafka、Flume和TCP套接字等;MLlib(机器学习):
MLlib提供了常用机器学习算法的实现,包括聚类、分类、回归、协同过滤等,
降低了机器学习的门槛,开发人员只要具备一定的理论知识就能进行机器学习的工作;GraphX(图计算):
GraphX是Spark中用于图计算的API,可认为是Pregel在Spark上的重写及优化,
Graphx性能良好,拥有丰富的功能和运算符,能在海量数据上自如地运行复杂的图算法。
Spark运行架构
一些基本概念(记住,很重要)
RDD:
是弹性分布式数据集(Resilient Distributed Dataset)的简称-
DAG:
是Directed Acyclic Graph(有向无环图)的简称,反映RDD之间的依赖关系;- 应用 Application:用户编写的Spark应用程序;
- 作业 Job:一个作业包含多个RDD及作用于相应RDD上的各种操作;
- 阶段 Stage:是作业的基本调度单位,一个作业会分为多个阶段,每个阶段包括多个任务
- 任务 Task:运行在Executor上的工作单元;
- Executor:是运行在工作节点(Worker Node)上的一个进程,负责运行任务,并为应用存储数据;
架构设计
一个应用(Application)由一个任务控制节点(Driver)和若干个作业(Job)构成,
一个作业由多个阶段(Stage)构成,一个阶段由多个任务(Task)组成。
当执行一个应用时,任务控制节点会向集群管理器(Cluster Manager)申请资源,
启动Executor,并向Executor发送应用程序代码和文件,然后在Executor上执行任务,
运行结束后,执行结果会返回给任务控制节点,或者写到HDFS或者其他数据库中。
运行基本流程
(1)当一个Spark应用被提交时,首先需要为这个应用构建起基本的运行环境,
即由任务控制节点(Driver)创建一个SparkContext,
由SparkContext负责和资源管理器(Cluster Manager)的通信以及进行资源的申请、任务的分配和监控等。
SparkContext会向资源管理器注册并申请运行Executor的资源;
(2)资源管理器为Executor分配资源,并启动Executor进程,Executor运行情况将随着“心跳”发送到资源管理器上;
(3)SparkContext根据RDD的依赖关系构建DAG图(RDD 的依赖关系、DAG 下面讲),DAG图提交给DAG调度器(DAGScheduler)进行解析,
将DAG图分解成多个“阶段”(每个阶段都是一个任务集),并且计算出各个阶段之间的依赖关系,
然后把一个个“任务集”提交给底层的任务调度器(TaskScheduler)进行处理;Executor向SparkContext申请任务,
任务调度器将任务分发给Executor运行,同时,SparkContext将应用程序代码发放给Executor;
(4)任务在Executor上运行,把执行结果反馈给任务调度器,然后反馈给DAG调度器,
运行完毕后写入数据并释放所有资源。
RDD的设计与运行原理:
RDD设计背景:
很多计算框架只能支持一些特定的计算模式,并没有提供一种通用的数据抽象。
RDD就是为了满足这种需求而出现的,它提供了一个抽象的数据架构,
不同RDD之间的转换操作形成依赖关系,可以实现管道化,从而避免了中间结果的存储,大大降低了数据复制、磁盘IO和序列化开销。
RDD概念
一个RDD就是一个分布式对象集合,每个RDD可以分成多个分区,每个分区就是一个数据集片段,
一个RDD的不同分区可以被保存到集群中不同的节点上,从而可以在集群中的不同节点上进行并行计算。
如何得到RDD?
1、RDD是只读的记录分区的集合,不能直接修改,只能基于稳定的物理存储中的数据集来创建RDD。
2、或者通过在其他RDD上执行确定的转换操作(如map、join和groupBy)而创建得到新的RDD。
数据运算:
- 行动(Action):执行计算并指定输出的形式
- 转换(Transformation):指定RDD之间的相互依赖关系
RDD经过一系列的“转换”操作,每一次都会产生不同的RDD,供给下一个“转换”使用;
RDD采用了惰性调用,即在RDD的执行过程中,真正的计算发生在RDD的“行动”操作,
对于“行动”之前的所有“转换”操作,Spark只是记录下“转换”操作应用的一些基础数据集以及RDD生成的轨迹,即相互之间的依赖关系,而不会触发真正的计算。
上述这一系列处理称为一个“血缘关系(Lineage)”,即DAG拓扑排序的结果。
采用惰性调用,通过血缘关系连接起来的一系列RDD操作就可以实现管道化(pipeline),
避免了多次转换操作之间数据同步的等待,而且不用担心有过多的中间数据,
因为这些具有血缘关系的操作都管道化了,一个操作得到的结果不需要保存为中间数据,
而是直接管道式地流入到下一个操作进行处理。
同时,这种通过血缘关系把一系列操作进行管道化连接的设计方式,
也使得管道中每次操作的计算变得相对简单,保证了每个操作在处理逻辑上的单一性
RDD特性
-
高效的容错性:
现有的分布式数据存储框架,为了实现容错必须在集群节点之间进行数据复制或者记录日志,也就是在节点之间会发生大量的数据传输,会带来很多IO上的开销。
为什么需要在多个节点间进行数据复制呢?
一方面是为了数据的备份,防止一个节点宕机导致数据丢失的问题另一方面是考虑了数据可能在多个节点进行处理,每个节点处理这个数据都需要进行复制,防止节点之间修改数据对互相产生影响。
在RDD的设计中,数据只读,不可修改,如果需要修改数据,必须从父RDD转换到子RDD,由此在不同RDD之间建立了血缘关系。所以,RDD是一种天生具有容错机制的特殊集合,如果数据丢失,只需通过RDD父子依赖(血缘)关系重新计算得到丢失的分区来实现容错
中间结果持久化到内存。
存放的数据可以是Java对象,避免了不必要的对象序列化和反序列化开销。
RDD之间的依赖关系:
RDD中不同的操作会使得不同RDD中的分区会产生不同的依赖。
RDD中的依赖关系分为窄依赖(Narrow Dependency)与宽依赖(Wide Dependency)。
对于窄依赖的RDD,可以以流水线的方式计算所有父分区,不会造成网络之间的数据混合。
对于宽依赖的RDD,则通常伴随着Shuffle操作,即首先需要计算好所有父分区数据,
然后在节点之间进行Shuffle 然后把 Shuffle 后的数据放到子分区。
两种依赖关系的区别
窄依赖的失败恢复更为高效,它只需要根据父RDD分区重新计算丢失的分区即可,
而且可以并行地在不同节点进行重新计算。
对于宽依赖而言,单个节点失效通常意味着重新计算过程会涉及多个父RDD分区,开销较大。
阶段的划分:
Spark通过分析各个RDD的依赖关系生成了DAG(这里提到DAG了,划重点!),
再通过分析各个 RDD 中的分区之间的依赖关系 来决定如何划分阶段
具体划分方法是:
在DAG中进行反向解析,遇到宽依赖就断开,遇到窄依赖就把当前的RDD加入到当前的阶段中;
窄依赖可以形成一个流水线操作,
比如,7->9->13 可以看成一个流水线,8->10->14 可以看成一个流水线,两个互不影响。
7 到 9,可以不用等待 8 到 10 这个转换操作的计算结束,
而是继续进行union操作,转换得到分区13,这样流水线执行大大提高了计算的效率。
把一个DAG图划分成多个“阶段”以后,每个阶段都代表了一组关联的、相互之间没有Shuffle依赖关系的任务组成的任务集合。
RDD运行过程:
通过上述对RDD概念、依赖关系和阶段划分的介绍,结合之前介绍的Spark运行基本流程,
这里再总结一下RDD在Spark架构中的运行过程:
(1)创建RDD对象;
(2)SparkContext负责计算RDD之间的依赖关系,构建DAG;
(3)DAGScheduler(DAG调度器)负责把DAG图分解成多个阶段,每个阶段中包含了多个任务,
每个任务会被任务调度器分发给各个工作节点(Worker Node)上的Executor去执行。
Spark三种部署方式
独立集群管理器(standalone)模式:
Spark框架本身也自带了完整的资源调度管理服务,可以独立部署到一个集群中,
而不需要依赖其他系统来为其提供资源管理调度服务。-
Spark on Mesos模式:
Mesos是一种资源调度管理框架,可以为运行在它上面的Spark提供服务由于Mesos和Spark存在一定的血缘关系
因此,Spark这个框架在进行设计开发的时候,就充分考虑到了对Mesos的充分支持
Spark运行在Mesos上,要比运行在YARN上更加灵活、自然 Spark on YARN模式
Spark可运行于YARN之上,与Hadoop进行统一部署,即“Spark on YARN”
资源管理和调度依赖YARN,分布式存储则依赖HDFS。
一般采用第三种模式,具有可以共享底层存储等 优点