概述
Apache Spark,全称伯克利数据分析栈,是一个开源的基于内存的通用分布式计算引擎,内部集成大量的通用算法,包括通用计算、机器学习、图计算等,用于处理大数据应用。
主要由下面几个核心构件组成,具体包括:
集群资源管理器(Muster Node)、任务控制节点(Driver)、任务执行节点(Worker Node)。
其中集群资源管理器可自由集成其他管理器(例如Yarn、Mesos、K8s等),目前一般主流生产环境都搭载在Yarn上运行。
Spark计算模型本质和MapReduce一样,也需要经过Map和Reduce两个过程,只是中间计算过程、计算依赖的编程模型、任务调度机制等,更加高效、快速、灵活。与Hadoop MapReduce计算框架相比,有下面几个优点:
1、采用多线程来执行具体的任务,MapReduce采用进程模型,减少进程切换的性能开销。
2、内部架构拥有一个BlackManager存储模块,会将内存和磁盘共同作为存储设备,中间计算结果可保存起来,MapReduce的中间计算结果都是落到HDFS文件里,减少IO开销。
3、内部计算都在内存里完成,MapReduce计算过程需要大量和磁盘进行交互,计算速度非常快。
4、任务调度机制采用有向无环图DAG,MapReduce采用迭代机制,可以共享中间计算结果
下面从如下几个方面介绍下其相关理论:
目录
一、架构
二、核心知识点
1、核心组件
SparkCore:将分布式数据抽象为弹性分布式数据集(RDD),实现了应用任务调度、RPC、序列化和压缩,并为运行在其上的上层组件提供API。
SparkSQL:操作结构化数据的程序包,可以使用SQL语句的方式来查询数据,Spark支持多种数据源,包含Hive,Hbase、RMDBS、Kafka、JSON等数据源。开发人员无须编写 MapReduce程序,直接使用SQL命令就能完成更加复杂的数据查询操作。
SparkStreaming: 提供实时的流式计算组件,支持高吞吐量、可容错处理的实时流式数据处理,其核心原理是将流数据分解成一系列短小的批处理作业,每个短小的批处理作业都可以使用 Spark Core进行快速处理。
MLlib:提供常用机器学习算法的实现库,包括分类、回归、聚类、协同过滤算法等,还提供了模型评估、数据导入等额外的功能,开发人员只需了解一定的机器学习算法知识就能进行机器学习方面的开发,降低了学习成本。
GraphX:提供一个分布式图计算框架,能高效进行图计算,拥有图计算和图挖掘算法的API接口以及丰富的功能和运算符,极大地方便了对分布式图的处理需求,能在海量数据上运行复杂的图算法。
BlinkDB:用于在海量数据上进行交互式SQL的近似查询引擎。
Tachyon:以内存为中心高容错的的分布式文件系统。
2、基本概念
Apache SparkContext
是Spark应用程序的核心,负责建立Spark的运行环境,通过提交Spark应用程序来驱动Spark配套服务完成作业计算任务。主要工作是:
获取Spark应用程序的当前状态
取消工作
取消Stage(一个阶段)
同步运行job
异步运行job
访问持久化的RDD
释放一个持久化的RDD
可编程动态资源分配
Apache Spark Shell
是用Scala编写的Spark应用程序,它提供Spark运行环境的命令行工具,便于管理Spark应用的执行
Spark Application
用户编写的Spark应用程序,包含了Driver Program以及在集群上运行的程序代码,物理机器上涉及了driver,master,worker三个节点。
Driver
Spark程序在Driver(进程)上执行,Driver进程所在的节点可以是Spark集群的某一个节点或者就是我们提交Spark程序的客户端节点,具体Driver进程在哪个节点上启动是由我们提交任务时指定的参数决定的。
Driver负责运行Application的main函数并创建SparkContext,由SparkContext负责与Cluster Manager通信,进行资源申请、任务的分配、监控等,当Executor部分运行完毕后Driver同时负责将SparkContext关闭。
Master
集群资源管理器中的主节点中启动的进程,主要负责集群资源的管理、分配、集群监控等,Master是一个物理节点。
Worker
集群资源管理器中的从节点中启动的进程,主要负责启动其它进程来执行具体数据的处理和计算任务,Worker是一个物理节点,在上面启动Executor进程执行Task。
Executor
Executor是一个执行Task的容器,由Worker负责启动,主要为了执行数据处理和计算,该进程负责运行Task,并且负责将数据存在内存或者磁盘上,每个任务都有各自独立的Executor。
作业(Job)
Job是并行计算的工作单元,由多个任务组成,这些任务是响应Apache Spark中的Actoion而产生的。
一个Job包含多个RDD及作用于相应RDD上的各种操作,它包含很多task的并行计算,可以认为是SparkRDD里面的action,每个action的触发会生成一个job。用户提交的Job会提交给DAGScheduler,Job会被分解成Stage,Stage会被细化成Task,Task简单的说就是在一个数据partition上的单个数据处理流程。
任务(Task)
由Executor负责启动,它是真正干活的,完成具体的计算任务。每个阶段都有一个任务,每个分区分配一个任务,同一任务是在RDD的不同分区上完成的。
在Spark中有两类task:
shuffleMapTask,输出是shuffle所需数据,stage的划分也以此为依据,shuffle之前的所有变换是一个stage,shuffle之后的操作是另一个stage。
resultTask,输出是计算结果,
比如:rdd.parallize(1 to 10).foreach(println)
这个操作没有shuffle,直接就输出了,那么只有它的task是resultTask,stage也只有一个。
比如:rdd.map(x=>(x,1)).reduceByKey(_+_).foreach(println)
这个操作有reduce,所以有一个shuffle过程,那么reduceByKey之前的是一个stage,执行shuffleMapTask,输出shuffle所需的数据,reduceByKey到最后是一个stage,直接就输出结果了。如果job中有多次shuffle,那么每个shuffle之前都是一个stage。
任务阶段(Stage)
是Job的基本调度单位,一个Job会分为多组Task,每组Task被称为一个Stage就像MapStage,ReduceStage,或者也被称为TaskSet,代表一组关联的、相互之间没有Shuffle依赖关系的任务组成的任务集。
每个Job都分成一些较小的任务集,称为相互依赖的阶段(Stage)。Stage被分类为计算边界,不能在单个Stage中完成所有计算,Job通过许多个阶段(Stage)来完成具体作业目标。
RDD之间有一系列的依赖关系,又分为窄依赖和宽依赖。简单的区分可以看一下父RDD中的数据是否进入不同的子RDD,如果只进入到一个子RDD则是窄依赖,否则就是宽依赖。如下图
窄依赖( narrow dependencies ):
子RDD 的每个分区依赖于常数个父分区(即与数据规模无关)
输入输出一对一的算子,且结果RDD 的分区结构不变,主要是map 、flatMap
输入输出一对一,但结果RDD 的分区结构发生了变化,如union 、coalesce