楔子
学习《Spark大数据分析技术与实战》
我主要是基于java实现,一些scala语言中的例子在java中没找到,就不写了
第3章 RDD编程
3.2 RDD的特性
Spark在定义和描述RDD的时候,通常会涉及以下五个接口,
接口 | 描述 |
---|---|
partition | 分区,一个RDD会有一个或者多个分区 |
perferredLocations§ | 对于分区p,返回数据所在优先位置信息 |
dependencies() | RDD的依赖关系 |
compute(p.context) | 对于分区P进行 |
partitioner() | RDD的分区函数 |
3.2.1 分区
RDD中的数据可能是TB,PB级别的,完全基于一个节点上的存储于计算并不现实。Spark基于分布式的思想,先将RDD划分为若干个子集,每个子集称为一个分区(partition),分区是RDD的基本组成单位,与MAPReduce中的split类似。对于一个RDD,Spark以分区为单位逐个计算分区中的元素。分区的多少决定了这个RDD进行并行计算的粒度,因为对RDD中每一个分区的计算都是一在一个单独的任务中执行的,用户可以显示指定RDD的分区数目,若不指定Spark将会采用默认值(CPU核数
)
3.2.2 依赖
RDD是易转换、易操作的,意味着用户可以从已有的RDD转换出新的RDD。新、旧RDD之间必定存在着某种联系,这种联系称为RDD的依赖关系。RDD间的依赖关系是Spark中的一个重要概念,是Spark进行容错、优化、任务调度的基础。
RDD的依赖关系分为2种:
窄依赖:父RDD的每个分区最多被其子RDD中的一个分区所依赖,也就是子RDD的每个分区依赖于常数个父分区,子RDD每个分区的生成与父RDD的数据规模无关。
宽依赖:父RDD的每个分区被其子RDD的多个分区依赖,子RDD每个分区的生成与父RDD的数据规模相关。
之所以要区分两种依赖:
一方面:对于若干个彼此宽窄依赖关系的RDD,基于任何一个子RDD分区可以方便地计算出其所有祖先RDD相应分区,这些RDD可以在集群的节点内存中以流水线的方式高效执行。
另一方面:对于窄依赖关系间的RDD,当子RDD的一个分区出错,可以方面地利用父RDD中对应的分区重新计算该错误分区,因此窄依赖关系使得数据容错与恢复非常方便;而对于宽依赖关系,子RDD的一个分区出错会导致其对应父RDD的多个分区重新计算,过程类似于MapReduce的suffle操作,代价高。
3.2.3 计算
Spark中每个RDD中都包含一个函数,即在父RDD上执行何种计算后得到当前RDD。每个RDD的计算都是以分区为单位的,而且每个RDD中的计算都是对迭代器进行复核,不需要每次都保存计算的结果。
3.2.4 分区函数
对于key-value形式的RDD,Spark允许用户根据关键字key指定分区顺序,这是一个可选的功能。目前支持哈希分区和范围分区,这一特性有助于提高RD之间某些操作的执行效率,例如可以指定两个RDD按照同样的哈希分区方式进行分区,当这两个RDD之间执行join操作时,会简化shuffle过程,提高效率。
3.2.5 优先位置
RDD优先位置属性与Spark中的作业调度与管理密切相关,是RDD中每个分区所存储的位置。遵循“移动计算不动数据”这一理念,Spark在执行任务时尽可能地将数据分配到相关数据块所在的节点上。以从Hadoop在执行任务时尽可能地将计算分配到相关数据块所在的节点上。以从Hadoop中读取数据生成RDD为例,preferredLocations返回每一个数据块所在的机器名或者IP地址,如果一个块数是多份存储的,那么将返回多个机器地址。
3.3 创建操作
RDD中封装的操作非常丰富,大致可以分为转换操作(Transformation)和执行操作(Action)。在已知RDD上执行转换操作可返回一个新的RDD,而执行操作则是向驱动器程序返回结果或把结果写入外部系统。转换操作采取了惰性策略,即转换操作不会立即被计算,其相当于业务逻辑的一种抽象描述,只是提交执行操作时,才会真正触发对转换操作的计算。
3.3.1 基于集合的创建操作
Spark提供了parallelize和makeRDD两个操作来实现从程序中的已有集合创建RDD。这两个操作功能类似,不同的是makeRDD还提供了一个可以指定每一分区preferredLocations参数的实现版本,makeRDD不仅将集合按顺序平均分片,还可以指定每一个RDD分区的优先位置,以便在后续的运行中优化调度。
3.3.2 基于外部存储的创建操作
Spark的整个生态系统与Hadoop是完全兼容的。Spark不仅可以将HDFS上的文件读取为分布式数据集,还支持其他所有实现了Hadoop接口的存储系统,Spark支持的hadoop输入格式包括文本文件,SequenceFile、Avro、Parquet等。
scContext.textFile("hdfs://had2/file/core-site.xml")
textFile只支持.gz格式的压缩文件。
textFile带有一个可选的分区参数。用户可以通过该参数指定创建RDD的分区数,但不能使用少于block个数。默认情况下Spark为每个HDFS中的block创建一个分区。
eg :创建分区为2的RDD
scContext.textFile("hdfs://had2/file/core-site.xml", 2)
3.4 常见的执行操作
执行操作(action)是向应用程序返回值或向存储系统导出数据的操作,常见的有first count collect take 等
3.5 常见转换操作
3.5.1 一元转换操作
-
map
map操作针对RDD中每个元素,进行指定函数运算,准换新的元素,所有新的元素构成新的RDD。
-
mapValues
该函数适用于key-value对形式的RDD,即RDD中的每个数据都是有序二元组,针对K-V 对中的values进行制定的函数运算(一对一映射)。得到新的values值,原RDD中的key保持不变,并与新的values构成新的k-v。
-
mapPartitions
该函数是一个map的一个变形。map的输入函数是用作RDD中每个元素,而mapPartitions的输入函数作用于每个分区
-
flatMap
flatMap 和mao类似,针对RDD中的每个元素,经过制定的函数(一对多映射)运算生成若干个新元素,所有新元素构成新RDD
-
flatMapValues
flatMapValues 类似于mapValues,适用于Key-value 对形式的RDD,对每个Key-value对中的Value值进行指定的函数运算,但是不同之处在于每个Value值可能被映射为若干个新值(不再是一对一映射),然后这些新值于原来的key组成新的key-values。
-
groupBykey
-
sortByKey
根据key值作为依据排序
-
reduceByKey
针对key-value形式的RDD,对具有相同key的value进行指定的函数运算,在将计算结果与key值组成一个新的key-value
-
filter
针对RDD中每一个元素进行指定的函数运算。对于返回值为true的元素,筛选出来作为新的RDD中的元素
3.5.2 二元转换操作
尽管RDD不是严格意义上的集合,但是同样支持许多数学上的集合运算。
-
union
该操作是将两个RDD中的元素进行合并。将结果封装成新的RDD。类似于两个集合的并运算。
-
intersection
相当于两个集合的交运算
-
subtract
相当于两个集合的差运算
3.6 持久化操作
默认情况下,对于每个经过一系列转换操作后得到的RDD,当在其上多次提交操作时,该RDD将会被重复计算。
var rdd =rdd1.map(func1).map(fun2).map(fun3).collect
在执行第一条语句时。rdd已经通过RDD1和三个map操作创建完成;当执行第二条语句时,rdd会被重复创建,即在此执行三个map操作。为了避免一个RDD的重复计算生成,可以使用持久化操作。Spark持久化操作支持在内存、磁盘上保存数据集或在集群间复制数据集,以便后续查询同一RDD时能够块数访问。
Spark中的持久化操作有cache、persist、checkpoint,其中persist是将数据持久化到磁盘或者内存;cache可视为persist的特例,将数据持久化到内存;checkpoint将数据持久化到磁盘上,于persist将数据持久化到硬盘上类似,但是checkpoint不在保存RDD间的依赖关系。
3.7 存储操作
利用Spark提供的saveAsFile等方法可以将RDD存储为HDFS文件。
第4章
4.1 Spark调度管理基本概念
-
Application
基于Spark应用程序,由一个或者多个作业组成。每个应用程序的执行涉及Driver program和集群上的Executors两部分。
-
Driver Program
Driver Program 包含了启动运行函数 main函数和一个SparkContext类型的实例。其中SparkContext实例是Application与Spark集群进行交互的唯一通道。是每一个Application的入口。Driver Program可以运行在任何可以提交作业的节点上(Worker Master),并不是必须运行在Master节点上。在实际生产环境中为了较少Master的负担,尽量避免在Master上提交Driver Program。
-
Worker
是Spark集群中任何可以运行Application相关代码的节点。
-
Executor
是Worker上为某个Application启动的一个进程,该进程复制执行任务并将负责数据存储在内存或者磁盘中。executor拥有CPU和内存资源。它是资源管理器系统能够给予的最小单位。一个Worker节点上可能有多个Executor,但是每个Executor中仅执行一个Application对于的任务。也就是说,不同的Application通过Executor无法共享数据。
-
Task
task即任务,是被送到Executor上执行的工作单元。RDD中的每个分区都对应相应的Task,而每个Task对应于executor中的一个线程。这使得系统更加轻量级,Task之间切换的时间延迟更短。
-
Job
Job即作业,是包含多个Task的并行计算,其与Application中的执行操作一一对应,也就是说Application每提交一个执行操作Spark对应生成一个Job。
-
Stage
通常执行操作之前会有若干个转换操作,而每个转换操作意味着父RDD到子RDD的转换,因此一个Job中通常涉及多个RDD。将Job中涉及的RDD进行分组,每组称为一个Stage
-
Cluster Manage
是在集群上获取资源的外部服务。若是Standalone模式的Spark集群,Cluster Manager即为Master;若是基于Yarn模式的Spark集群,Cluster Manager即为Resource Manager。