导读:Spark是由加州大学伯克利分校AMP实验室开源的分布式大规模数据处理通用引擎,具有高吞吐、低延时、通用易扩展、高容错等特点。Spark内部提供了丰富的开发库,集成了数据分析引擎Spark SQL、图计算框架GraphX、机器学习库MLlib、流计算引擎Spark Streaming。
Spark在函数式编程语言Scala中实现,提供了丰富的开发API,支持Scala、Java、Python、R等多种开发语言。同时,Spark提供了多种运行模式,既可以采用独立部署的方式运行,也可以依托Hadoop YARN、Apache Mesos等资源管理器调度任务运行。
目前,Spark已经在金融、交通、医疗、气象等多种领域中广泛使用。
作者:肖冠宇
如需转载请联系大数据(ID:hzdashuju)
01 Spark概述
1. 核心概念介绍
Spark架构示意图如图2-1所示,下面将分别介绍各核心组件。
Client:客户端进程,负责提交作业。
Driver:一个Spark作业有一个Spark Context,一个Spark Context对应一个Driver进程,作业的main函数运行在Driver中。Driver主要负责Spark作业的解析,以及通过DAGScheduler划分Stage,将Stage转化成TaskSet提交给TaskScheduler任务调度器,进而调度Task到Executor上执行。
Executor:负责执行Driver分发的Task任务。集群中一个节点可以启动多个Executor,每一个Executor可以执行多个Task任务。
Catche:Spark提供了对RDD不同级别的缓存策略,分别可以缓存到内存、磁盘、外部分布式内存存储系统Tachyon等。
Application:提交的一个作业就是一个Application,一个Application只有一个Spark Context。
Job:RDD执行一次Action操作就会生成一个Job。
Task:Spark运行的基本单位,负责处理RDD的计算逻辑。
Stage:DAGScheduler将Job划分为多个Stage,Stage的划分界限为Shuffle的产生,Shuffle标志着上一个Stage的结束和下一个Stage的开始。
TaskSet:划分的Stage会转换成一组相关联的任务集。
RDD(Resilient Distributed Dataset):弹性分布式数据集,可以理解为一种只读的分布式多分区的数组,Spark计算操作都是基于RDD进行的,下面会有详细介绍。
DAG(Directed Acyclic Graph):有向无环图。Spark实现了DAG的计算模型,DAG计算模型是指将一个计算任务按照计算规则分解为若干子任务,这些子任务之间根据逻辑关系构建成有向无环图。
▲图2-1 Spark架构示意图
2. RDD介绍
RDD从字面上理解有些困难,我们可以认为是一种分布式多分区只读的数组,Spark计算操作都是基于RDD进行的。
RDD具有几个特性:只读、多分区、分布式,可以将HDFS块文件转换成RDD,也可以由一个或多个RDD转换成新的RDD,失效自动重构。基于这些特性,RDD在分布式环境下能够被高效地并行处理。
(1)计算类型
在Spark中RDD提供Transformation和Action两种计算类型。Transformation操作非常丰富,采用延迟执行的方式,在逻辑上定义了RDD的依赖关系和计算逻辑,但并不会真正触发执行动作,只有等到Action操作才会触发真正执行操作。Action操作常用于最终结果的输出。
常用的Transformation操作及其描述:
map (func):接收一个处理函数并行处理源RDD中的每个元素,返回与源RDD元素一一对应的新RDD
filter (func):并行处理源RDD中的每个元素,接收一个处理函数,并根据定义的规则对RDD中的每个元素进行过滤处理,返回处理结果为true的元素重新组成新的RDD
flatMap (func):flatMap是map和flatten的组合操作,与map函数相似,不过map函数返回的新RDD包含的元素可能是嵌套类型,flatMap接收一个处理嵌套会将嵌套类型的元素展开映射成多个元素组成新的RDD
mapPartitions (func):与map函数应用于RDD中的每个元素不同,mapPartitions应用于RDD中的每个分区。mapPartitions函数接收的参数为func函数,func接收参数为每个分区的迭代器,返回值为每个分区元素处理之后组成的新的迭代器,func会作用于分区中的每一个元素。有一种典型的应用场景,比如待处理分区中的数据需要写入到数据库,如果使用map函数,每一个元素都会创建一个数据库连接对象,非常耗时并且容易引起问题发生,如果使用mapPartitions函数只会在分区中创建一个数据库连接对象,性能提高明显
mapPartitionsWithIndex(func):作用与mapPartitions函数相同,只是接收的参数func函数需要传入两个参数,分区的索引作为第一个参数传入,按照分区的索引对分区中元素进行处理
union (otherDataset):将两个RDD进行合并,返回结果为RDD中元素(不去重)
intersection (otherDataset):对两个RDD进行取交集运算,返回结果为RDD无重复元素
distinct ([numTasks])):对RDD中元素去重
groupByKey ([numTasks]):在KV类型的RDD中按Key分组,将相同Key的元素聚集到同一个分区内,此函数不能接收函数作为参数,只接收一个可选参数任务数,所以不能在RDD分区本地进行聚合计算,如需按Key对Value聚合计算,只能对groupByKey返回的新RDD继续使用其他函数运算
reduceByKey (func, [numTasks]):对KV类型的RDD按Key分组,接收两个参数,第一个参数为处理函数,第二个参数为可选参数设置reduce的任务数。reduceByKey函数能够在RDD分区本地提前进行聚合运算,这有效减少了shuffle过程传输的数据量。相对于groupByKey函数更简洁高效
aggregateByKey (zeroValue)(seqOp, combOp):对KV类型的RDD按Key分组进行reduce计算,可接收三个参数,第一个参数是初始化值,第二个参数是分区内处理函数,第三个参数是分区间处理函数