RDD(Resilient Distributed Dataset)弹性分布式数据集,RDD从字面理解,分为三个层面:弹性、分布式、数据集。
RDD是一种数据集,是Spark对于要处理的数据的抽象,就像Java等高级编程语言中的List、HashMap等集合;
分布式是因为我们通常是以集群形式进行分布式计算,RDD中的数据并非存在一个节点,而是分布于集群各个节点,便于调用各个节点的算力;
RDD的弹性,则涉及较多,如数据分片和调度的弹性、自动进行内存和磁盘数据存储切换的弹性等。
一言以蔽之,RDD是Spark进行数据处理所使用的特殊数据类型。
注意:RDD时只读类型,对RDD的任何操作都不改变RDD本身,只会产生新的RDD。
RDD的数据来源有以下几种:
val arrayRDD: RDD[Int] = sparkContext.parallelize(1 to 10)
# HDFS
val hdfsTxtRDD: RDD[String] = sparkContext.textFile("hdfs://localhost:9000/data/test.txt")
# 本地文件
val localTxtRDD: RDD[String] = sparkSession.sparkContext.textFile("C:/Users/86180/Desktop/*.txt")
外部数据路径可以指定目录,也可以使用通配符。
val rddNew: RDD[Int]=arrayRDD.map(i->i*2)
一个RDD以Block形式分布在集群各个节点
集群各个节点都有一个Manager专门管理Block
当发生RDD出现创建时,从节点的BlockManager会向主节点的BlockManger发起注册
当RDD不再需要时,主节点会向从节点发送删除指令
可以看出,主节点的BlockManager只负责管理RDD与Block的关系,并进行操作调度,而不管理Block
针对RDD的操作,主要分为转换操作和行动操作两类,其区别在于是否真正进行计算,转换操作并不执行计算,只有当发起行动操作时才会执行。
了解Java的会发现对RDD的操作,非常类似于文件流Stream的相关操作,如map、filter、count、collect等方法。
转换操作只记录RDD的变换轨迹,类似于制定行动方案,行动操作则相当于执行方案。
常用的RDD操作主要有以下几个算子:
映射操作map与flatMap函数 https://blog.csdn.net/weixin_42078760/article/details/106981781
过滤操作filter与filterNot函数 https://blog.csdn.net/weixin_42078760/article/details/106982020
规约操作reduce与fold函数 https://blog.csdn.net/weixin_42078760/article/details/106982030
拆分操作partition、grouped、groupBy和sliding函数 https://blog.csdn.net/weixin_42078760/article/details/106982271
当RDD进行大量迭代运算或需要重复执行某些计算时,如果每次都从头开始,则会造成很大的资源浪费,而且耗时,效率较低,因而可以在适当的时候对运算的中间结果进行缓存或者持久化,以避免重复计算。
RDD的缓存和持久化支持不同级别的存储方式:
MEMORY_ONLY Java对象形式存储于JVM内存,内存不足时,部分数据不再缓存,需要时重新计算
DISK_ONLY 存储于磁盘
MEMORY_AND DISK Java对象形式存储于JVM内存,内存不足时存储于磁盘
MEMORY_ONLY_SER Java对象序列化后存储于JVM内存,内存不足时,部分数据不在缓存
MEMORY_AND_DISK_SER Java对象序列化存储于JVM内存,内存不足时,存储到磁盘
MEMORY_ONLY_2/MEMORY_AND_DISK_2 数据备份到两个节点
OFF_HEAP 序列化后存储于Tachyon,可以减少垃圾回收开销
在实际使用中,选择缓存和持久化方式,实际上就是选择内存和CPU的平衡度。
当RDD数据量较小时,可以使用内存进行缓存,即MEMORY_ONLY
内存不够但CPU强劲时,可以使用序列化内存缓存,即MEMORY_ONLY_SER
尽量不要使用磁盘持久化,除非计算过程中会过滤掉大量数据或计算比较麻烦
如果需要快速失败恢复,则使用备份存储,即MEMORY_ONLY_2/MEMORY_AND_DISK_2
RDD通过检查点checkpoint进行容错,当设置checkpoint后,并不会立刻执行检查,当执行行动操作时,会在指定目录下创建二进制文件,将RDD持久化存储到磁盘。
当RDD依赖级别非常长,当多个任务使用同一个中间RDD时,且内存无法同时缓存多个中间RDD时,可以将依赖关系切分,进行存储。
简而言之,checkpoint主要用于依赖级别太长时。
RDD的操作都是被分片进行计算处理,一个RDD在经过多个操作后产生一个新的RDD,RDD会形成父子依赖关系,RDD的分片partition也会产生依赖关系。这种依赖关系分为两种:窄依赖和宽依赖。
简单来说,窄依赖的每个父级RDD分片最多被一个子RDD分片使用,宽依赖的每个父级RDD会被多个子RDD分片使用。
窄依赖分为两种:一对一依赖(OenToOneDependency)和范围依赖(RangeDependency)。
能形成一对一依赖的操作有map、filter等,形成范围依赖的操作有union等。
宽依赖涉及shuffle操作,能形成宽依赖关系的操作有groupbykey、reducebykey和join等。
数据优先放在内存中,如果内存不够用,会放到磁盘中。
分片数据之间互不影响,每个操作只关联父级操作,若出错,仅需通过数据检查点或记录的数据更新恢复单个分片即可。
默认重试次数为4次。
默认重试次数为4次。
通过checkpoint方法进行数据检查,通过persist方法进行持久化。
有向无环图计划(DAG)可以将多Stage任务串联或并行执行,不用保存中间结果,当单节点发生故障时,可用节点接替。
处理过程中存在数据碎片,如果每个碎片调用一个线程处理,则效率很低,且耗资源,可以通过合并数据分片提升效率。