Spark模块设计
整个Spark主要由Spark Core,Spark SQL,Spark Streaming,GraphX,MLlib组成,Spark Core是整个Spark体系的核心引擎,Spark SQL,Spark Streaming,GraphX,MLlib都是建立在Spark Core基础之上的.
Spark的核心功能
Spark Core中提供了Spark最基础最核心的功能,主要包括一下几项:
- 基础设施
在Spark中有很多基础设施,被Spark中的各种组件广泛使用.这些基础设施包括Spark 配置(SparkConf),Spark内置的RPC框架(在早期版本使用的是Akka),事件总线(ListenerBus),度量系统.
- SparkConf用于管理Spark应用程序的各种配置信息,在SparkConf中使用字符串键值对进行存储.
- Spark内置的RPC框架使用Netty实现,有同步和异步多种实现,Spark 各个组件之间的通信都依赖RPC框架.
- 如果说RPC框架是跨机器节点不同组件之间的通信设施,那么事件总线就是SparkContext内部各个组件之间的事件----监听器模式异步调用实现的.
- 度量系统由Spark中的多种度量源(Source)和多种度量输出(Sink)构成,完成对整个Spark集群中各个组件运行期状态的监控.
- 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)等组成.
- MemoryManager除了对存储系统中的存储内存提供支持和管理外,还为计算引擎中的执行内存提供支持和管理
- Tungsten除了用于存储外,也可以用于计算或执行.
- TaskMemoryManager对分配给单个Task的内存资源进行更细粒度的管理和控制.
- ExternalSorter用于在map端或者reduce端对ShuffleMapTask计算得到的中间结果进行排序,聚合等操作.
- ShuffleManager用于将各个分区对应的ShuffleMapTask产生的中间结果持久化到磁盘,并在reduce端按照分区远程拉取ShuffleMapTask产生的中间结果.
Spark扩展功能
- 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目前已经提供了统计基础,分类,回归,决策树,随机深林,朴素贝叶斯,保序回归,协同过滤,聚类,维数缩减,特征提取与转型,频繁模式挖掘,语言模型标记语言,管道等多种数理统计,概率论,数据挖掘方面的数据算法.
Spark模型设计
- Spark编程模型
Spark应用程序从编写到提交,执行,数据的整个过程如图:
步骤如下:
- 用户使用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计算模型
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基本架构
从集群部署的角度来看,Spark集群由集群管理器(Cluster Manager),工作节点(Worker),执行器(Executor),驱动器(Driver),应用程序(Application)等部分组成,它们之间的整体关系如图所示:
- Cluster Manager Spark的集群管理器,主要负责对整个集群资源的分配和管理,Cluster Manager在YARN部署模式下为ResourceManager;在Mesos部署模式下围为Mesos Master;在Standalone部署模式下为Master.Cluster Manager分配的资源属于一级分配,它将各个Worker上的内存,CPU等资源分配给Application,但是并不负责对Executor的资源分配.Standalone部署模式下的Master会直接给Application分配内存,CPU以及Executor等资源.目前Stabdalone,YARN,Mesos,EC2等都可以作为Spark的集群管理器.
- Worker Spark的工作节点.在YARN部署模式下实际由NodeManager代替.Worker节点主要负责以下工作:将自己的内存,cpu等资源通过注册机制告知Cluster Manager;创建Executor;将资源和任务进一步分配给Executor;同步资源信息,Executor状态信息给Cluster Manager等.在Stabalone部署模式下,Master将Worker上的内存,CPU以及Executor等资源分配给Application后,将命令Worker启动CoraseGrainedExecutorBackend进程(此进程会创建Executor实例)
- Executor 执行计算任务的一线组件.主要负责任务的执行以及与Worker,Driver的信息同步.
- Driver Application的驱动程序,Application通过Driver与Cluster Manager,Executor进行通信,Driver可以运行在Application中,也可以由Application提交给Cluster Manager并由ClusterManager安排Worker运行.
- Application 用户使用Spark提供的API编写的应用程序,Application通过SparkAPI 将进行RDD的转换和DAG的创建,并通过Driver将Application注册到ClusterManager,ClusterManager将会根据Application的资源需求,通过一级分配将Executor,内存,CPU等资源分配给Application.Driver通过二级分配将Executor等资源分配给每一个任务,Application最后通过Driver告诉Executor运行任务.