简介
什么是Spark
Spark特点
1)Speed:相比于MR,官方说,基于内存计算spark要快mr100倍,基于磁盘计算spark要快mr10倍。如图-1所示。
图-1 Spark和Hadoop运行速度比较
2)Ease of Use:Spark提供超过80多个高阶算子函数,来支持对数据集的各种各样的计算,使用的时候,可以使用java、scala、python、R,非常灵活易用。
df = spark.read.json(“logs.json”) df.where(“age > 21”)
.select(“name.first”) .show()
3)Generality:通用性如图-2所示。
图-2 Spark通用性特点
4)Runs Everywhere:Spark程序可以再多个平台上面运行,如图-3所示。
图-3 Spark到处运行
Spark概述总结
什么是Spark呢?它就是一个集成离线计算,实时计算,SQL查询,机器学习,图计算为一体的通用的计算框架。
何为通用?就是在一个项目中,既可以使用离线计算,也可以使用其他比如,SQL查询,机器学习,图计算等等,而这是Spark最最最强大的优势,没有之一。
而这一切的基础是SparkCore,速度比传统的mr快的原因就是基于内存的计算。
Spark开发过程中,使用到的模型——RDD(Resilient Distributed Dataset,弹性分布式数据集),在编程中起到了非常重要的作用。
RDD概述
何为RDD?其实RDD就是一个不可变的scala的并行集合。
Spark的核心概念就是RDD,指的是一个不可变、可分区、里面元素可并行计算的集合,这个数据的全部或者部分可以缓存在内存中,在多次计算间被重用。
RDD在抽象来说是一种元素集合,包含了数据。他是被分区的,分为多个分区,每个分区分布在集群中的不同worker节点上面,从而让RDD中的数据可以被并行操作。
RDD通常通过Hadoop上的文件,即HDFS文件或者Hive表来进行创建;也可以通过RDD的本地创建转换而来。
传统的MapReduce虽然具有自动容错、平衡负载和可拓展性的优点,但是其最大缺点是采用非循环式的数据流模型,使得在迭代计算式要进行大量的磁盘IO操作。RDD正式解决这个缺点的抽象方法。
RDD最重要的特性就是,提供了容错性,可以自动从节点失败中恢复过来。即如果某个节点上的RDD Partition,因为节点故障,导致数据丢失,那么RDD会自动通过自己的数据来源重新计算该Partition。这一切对使用者是透明的,这一切的背后工作都是通过RDD的lineage特性来实现的。
RDD的数据默认情况下是存放在内存中的,但是内存资源不足的时候,Spark会自动将RDD数据溢出到磁盘(弹性)。
RDD特性
通过上述的描述,我们可以从以下几个方面来描述RDD。
弹性
如果内存充足,那集合数据的存储和计算,就都在内存中完成;如果内存不足,需要有一部分数据溢出到磁盘,然后在磁盘完成存储和计算。
分布式
就和之前学习的分布式概念一样,一个集合的数据被拆分成多个部分,这每一个部分被称之为一个分区partition,还是一个scala的不可变的集合。默认情况下,partition是和hdfs中data-block块对应的,spark加载hdfs文件时,一个data-block块对应一个partition。所以,对RDD的操作,本质上是对着每一个RDD对应分区partition的操作。
数据集
存放数据的集合,而Spark就是对这个RDD及其集合功能算子的实现。RDD,弹性式分布式数据集,是Spark的第一代编程模型,说白了RDD就是一个抽象数据类型。
RDD之间是存在依赖关系的
这些RDD之间的依赖关系,就形成了一个RDD的有向无环图DAG,依赖关系称之为RDD血缘关系或者血统,因为lineage。
依赖关系呢,分为了两种:窄依赖和宽依赖。具体我们会在spark stage阶段划分的时候进行具体说明。
移动计算优于移动数据
partition提供的最佳计算位置,利于数据处理的本地化即计算向数据移动而不是移动数据。总结如图-4所示。
图-4 RDD五大特性
1)一组分片(Partition),即数据集的基本组成单位。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建RDD时指定RDD的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的CPU Core的数目。
2)一个计算每个分区的函数。Spark中RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。
3)RDD之间的依赖关系。RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD的所有分区进行重新计算。
4)一个Partitioner,即RDD的分片函数。当前Spark中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于key-value的RDD,才会有Partitioner,非key-value的RDD的Parititioner的值是None。Partitioner函数不但决定了RDD本身的分片数量,也决定了parent RDD Shuffle输出时的分片数量。
5)一个列表,存储存取每个Partition的对应数据的优先位置(preferred location)。对于一个HDFS文件来说,这个列表保存的就是每个Partition所在的块的位置。按照“移动数据不如移动计算”的理念,Spark在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置。
RDD在Spark中的地位和作用
1)为什么会有Spark?因为传统的并行计算模型无法有效的进行交互式计算;而Spark的使命便是解决这个问题,这也是它存在的价值和理由。
2)Spark如何解决迭代计算?其主要实现思想就是RDD,把所有计算的数据保存在分布式的内存中。迭代计算通常情况下都是对同一个数据集做反复的迭代计算,数据在内存中将大大降低IO操作。这也是Spark设计的核心:内存计算。
3)Spark如何实现交互式计算?因为Spark是用scala语言实现的,Spark和scala能够紧密的集成。所以Spark可以完美的运用scala的解释器,使得其中的scala可以向操作本地集合对象一样轻松的操作分布式数据集。
4)Spark和RDD的关系:可以理解为RDD是一种具有容错性,基于内存的集群计算抽象方法,Spark则是这个抽象方法的实现。