Spark 简介

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特性
  1. 高效的容错性:
    现有的分布式数据存储框架,为了实现容错必须在集群节点之间进行数据复制或者记录日志,也就是在节点之间会发生大量的数据传输,会带来很多IO上的开销。
    为什么需要在多个节点间进行数据复制呢?
    一方面是为了数据的备份,防止一个节点宕机导致数据丢失的问题

    另一方面是考虑了数据可能在多个节点进行处理,每个节点处理这个数据都需要进行复制,防止节点之间修改数据对互相产生影响。

    在RDD的设计中,数据只读,不可修改,如果需要修改数据,必须从父RDD转换到子RDD,由此在不同RDD之间建立了血缘关系。所以,RDD是一种天生具有容错机制的特殊集合,如果数据丢失,只需通过RDD父子依赖(血缘)关系重新计算得到丢失的分区来实现容错

  2. 中间结果持久化到内存。

  3. 存放的数据可以是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。

一般采用第三种模式,具有可以共享底层存储等 优点

你可能感兴趣的:(Spark 简介)