整个Spark主要由Spark Core,Spark SQL,Spark Streaming,GraphX,MLlib组成,Spark Core是整个Spark体系的核心引擎,Spark SQL,Spark Streaming,GraphX,MLlib都是建立在Spark Core基础之上的.
Spark Core中提供了Spark最基础最核心的功能,主要包括一下几项:
基础设施
在Spark中有很多基础设施,被Spark中的各种组件广泛使用.这些基础设施包括Spark 配置(SparkConf),Spark内置的RPC框架(在早期版本使用的是Akka),事件总线(ListenerBus),度量系统.
SparkContext
通常而言,用户开发的Spark应用程序的提交与执行都离不开SparkContext的支持,在正式提交应用程序之前,首先需要初始化SparkContext.SparkContext隐藏了网络通信,分布式部署,消息通信,存储体系,计算引擎,文件服务,WebUI等内容,应用程序开发者只需要使用SparkContext提供的API完成功能开发.
SparkEnv
Spark执行环境SparkEnv是Spark中的Task运行所必须的组件,SparkEnv内部封装了RPC环境(RpcEnv),序列化管理器,广播管理器(BroadcastManager),map任务输出跟踪器(MapOutputTracker),存储体系,度量系统(MetricsSystem),输出提交协调器(OutputCommitCoordinator)等Task运行所需要的各种组件.
存储体系
Spark优先考虑使用各节点的内存作为存储,当内存不足时才会考虑使用磁盘,这极大的减少了磁盘IO,提升了任务执行的效率,使得Spark适用于实时计算,迭代计算,流式计算等场景.在实际场景中,有些Task是存储密集型的,有些则是计算密集型的,所以有时候会造成存储空间空闲,而计算空间的资源又很紧张.Spark的内存存储空间与执行空间之间的边界可以是软边界,资源紧张的一方可以借用另一方的空间,这即可以有效的利用资源,又可以提高Task的执行效率.此外,Spark的内存空间还提供了Tungsten的实现,直接操作操作系统的内存.由于Tungsten省去了在堆内分配Java对象,因此能更加有效的利用系统的内存资源,并且因为直接操作擦系统内存,空间的分配和释放也更迅速.
调度系统
调度系统主要由DAGScheduler和TaskScheduler组成,他们都内置在SparkContext中.DAGSchedler负责创建Job,将DAG中的RDD划分到不同的Stage,给Stage创建对应的Task,批量提交Task等功能.TaskScheduler负责按照FIFO或者FAIR等调度算法对批量的Task进行调度,为Task分配资源,将Task发送到集群管理的当前应用的Executor上,由Executor负责执行工作.
计算引擎
计算引擎由内存管理器(MemoryManager),Tungsten,任务内存管理器(TaskMemoryManager),Task,外部排序器(ExternalSorter),Shuffle管理器(ShuffleManager)等组成.
SparkSQL
由于SQL具有普及率高,学习成本低等特点,为了Spark的应用面,还增加了对SQL以及Hive的支持,Spark SQL的过程可以总结为:首先使用SQL语句解析器(SqlParser)将SQL转换为语法树(Tree),并且使用规则执行器(RuleExecutor)将一系列规则(Rule)应用到语法树,最终生成物理执行计划并执行执行的过程.其中,规则包括语法分析器(Analyzer)和优化期(Optimizer).Hive的执行过程与SQL类似.
Spark Streaming
Spark Streaming与Apache Storm类似,也用于流式计算.Spark Streaming 支持Kafka,Flume和简单的TCP套接字等多种数据输入源.输入接收器(Receiver)负责接入数据,是接入数据的接口规范.DStream是Spark Streaming 中所有数据流的抽象,DStream可以被组织成DStream Graph.DStream本质上有一系列连续的RDD组成.
GraphX
Spark 提供的分布式图计算框架.GraphX主要遵循整体同步并行计算模式(BulkSynchronous Parallel,BSP)下的Pregel模式实现.GraphX提供了对图Graph的抽象,Graph由顶点(Vertex),边(Edge)以及继承了Edge的EdgeTriplet(添加了srcAttr和dstAttr,用来保存源顶点和目的顶点的属性)三种结构组成.GraphX目前已经封装了最短路径,网页排名,连接组件,三角关系统计等算法的实现.
MLlib
MLlib是Spark提供的机器学习框架.机器学习是一门涉及概率论,统计学,逼近论,凸分析,算法复杂度理论等多领域的交叉学科,MLlib目前已经提供了统计基础,分类,回归,决策树,随机深林,朴素贝叶斯,保序回归,协同过滤,聚类,维数缩减,特征提取与转型,频繁模式挖掘,语言模型标记语言,管道等多种数理统计,概率论,数据挖掘方面的数据算法.
步骤如下:
- 用户使用SparkContext提供的API编写的Driver应用程序.此外,SparkSession,DataFrame,SQLContext,HiveContext以及StreamingContext都对SparkContext进行了封装,并提供了DataFrame,SQL,Hive以及流式计算相关的API.
- 使用SparkContext提交的应用程序,首先会通过RpcEnv向集群管理器(Cluster Manager)注册应用(Application)并且告知集群管理器需要的资源数量.集群管理器根据Application的需求,给Application分配Executor资源,并在Worker上启动CoareseGrainedExecutorBackend进程(该进程内部将创建Executor).Executor所在的CoarseGrainedExecutorBackend进程在启动的过程中将通过RpcEnv直接向Driver注册Executor的资源信息,TaskScheduler将保存已经分配给应用的Executor资源的地址,大小等相关的信息,然后SparkContext根据各种转换API,构建RDD之间的血缘关系和DAG,RDD构建的DAG将最终提交给DAGScheduler,DAGScheduler给提交的DAG创建Job,并根RDD依赖性质将DAG划分为不同的Stage.DAGScheduler根据Stage内RDD的Partition数量创建多个Task并批量提交给TaskScheduler.TaskScheduler对批量的Task按照FIFO或者FAIR调度算法进行调度,然后给Task分配Executor资源,最后将Task发送给Executor由Executor执行.此外,SparkContext还为在RDD转换开始之前使用BlockManager和BroadcastManager将任务的Hadoop配置进行广播.
- 集群管理器(Cluster Manager)会根据应用的需求,给应用分配资源,即将具体的任务分配到不同的Worker节点上的多个Executor来处理任务的运行.Standalone,YARN,Mesos,EC2等都可以作为Spark的集群管理器.
- Task在运行的过程中需要对一些数据(如中间结果,检查点等)进行持久化,Spark支持选择HDFS,AmazonS3,Alluio(原名叫Tachyon)等作为存储.
RDD可以看做是对各种数据计算模型的统一抽象,Spark的计算过程主要是RDD的迭代计算过程,如下图所示.RDD的迭代计算过程类似于管道.分区数取决于Partition数量的设定,每个分区的数据只会在一个Task中计算,所有分区可以在多个机器节点的Executor上并执行.
上图只是简单的从从分区得角度将RDD的计算看做是管道,如果从RDD得血缘关系,Stage划分的角度来看,由RDD构成的DAG经过DAGScheduler调度后,将变成如图所示的样子.
上图共展示了 A B C D E F G一个7个RDD,每个RDD中的小方块代表一个分区,将会有一个Task处理此分区的数据.RDD A经过groupByKey转换后得到RDD B.RDD C经过map转换后得到RDD D,RDD D和RDD E进过union转换得到RDD F.RDD B和RDD F经过join转换后得到RDD G.从上图可以看到,map和union生成的RDD与其上游RDD之间的关系是NarrowDependency,而groupByKey和join生成的RDD与其上游的RDD之间的依赖关系是ShuffleDependency.由于DAGScheduler按照ShuffleDependency作为Stage的划分依据,因此A被划入了ShuffleMapTage1,C,D,E,F被划入了ShuffleMapStage2,B和G被划入ResultStage3.
从集群部署的角度来看,Spark集群由集群管理器(Cluster Manager),工作节点(Worker),执行器(Executor),驱动器(Driver),应用程序(Application)等部分组成,它们之间的整体关系如图所示: