一、RDD是什么?
1、简述RDD是什么?
- 弹性分布式数据集: resilient distributed dataset (RDD)
- 弹性:RDD的数据可以被缓存在内存中,长久存在。如果内存不足,可以将数据缓存在磁盘中。
- 分布式:这个集合中的数据是分散在不同机器节点上的。
- 数据集:数据的集合。
- 总结:就是一个可以将数据存储在分布式内存中的数据集合。
- 功能:用于实现将Spark计算的数据构建分布式,实现分布式的任务计算。
- Spark将所有读取进来的数据都封装在RDD这个数据结构中,变成分布式的数据。
- RDD:类比成一个分布式的List集合,这个集合的数据可以存储在多台机器
官网对此的描述: Resilient Distributed Datasets (RDDs)
2、RDD的五大特性
- 任何一个RDD都可以由一系列的分区构成
- 对RDD应用函数操作,实际会对这个RDD的每个分区进行操作
- 任何一个RDD都会记录依赖关系
- 高容错
- 如果RDD有数据丢失,可以通过依赖重新构建这份数据
- 对于KV类型的RDD,可以选择自定义分区方式
- 对于所有Task的运行,会计算最优路径
- 就是决定Task如何分配运行
- 设计思想:移动存储不如移动计算
二、RDD的容错及依赖
1、RDD容错机制
-
如何 保证RDD的数据安全,如果RDD的分区数据丢失,怎么恢复
-
方案一:依赖关系
- 如果RDD分区数据丢失了,可以通过依赖关系重构这个RDD
- 缺点:每一次如果都重构,性能比较差
-
方案二:持久化到缓存
- persist:将RDD的数据缓存在内存中以及磁盘中
- 如果RDD分区数据丢失,可以直接从缓存中获取
- 问题:是否是绝对安全的方案?
- 不是的
- 如果数据缓存在内存,内存的数据是易丢失
- 如果缓存在磁盘,磁盘也是易损坏的
- 缓存的数据也可能丢失
-
方案三:持久化到HDFS
- 将RDD的数据持久化在HDFS上,通过副本保证这个RDD的数据安全
- 每次读取,如果内存中没有或者丢失,可以直接从HDFS上读取到该数据
- 性能和安全只能二选一:每次都是从磁盘读
- 为RDD设置检查点,持久化到hdfs
代码:
#设置spark程序的检查点目录:将rdd数据存储在hdfs什么位置
sc.setCheckpointDir("/spark/chkpoint")
#创建rdd
val dataRdd = sc.textFile("/wordcount/input")
#将rdd设置持久化到HDFS
dataRdd.checkpoint
#测试
- persist与checkpoint
- persist
- 将数据持久化到内存中,易丢失的
- 性能比较好。
- 在缓存RDD到内存的时候,是需要保留RDD的依赖关系的
- 如果缓存丢失,需要通过血脉重新构建缓存数据
- checkpoint
- 将rdd数据持久化到hdfs,数据不易丢失。更加安全。
- 性能相对较差。
- 只保存RDD的数据,不需要保存依赖关系。
- 必须定期的手动清理,不会自动释放的。
2、RDD的依赖关系
- 所有的RDD都会记录自己的依赖关系:记录当前RDD是怎么来的
- 并行化集合:依赖于集合
- 读取外部数据源:依赖于数据源
- 转换函数:依赖于每一层的RDD
- 转换
- 父RDD:原始RDD
- 子RDD:通过转换函数得到的RDD
- 这两个RDD之间的关系:RDD的依赖
- 子RDD是依赖于父RDD
- 父RDD与子RDD的依赖关系的分类
- 宽依赖:会产生shuffle
- 窄依赖:不会产生shuffle
2-1、窄依赖:narrow dependencies
- 场景
- 一对一:一个父RDD的分区对应一个子RDD的分区
- 多对一:多个父RDD的分区对应 一个子RDD的分区
- 优点
- 不经过shuffle,内存直接到内存,不需要实现分区内数据的交叉。
- 当数据丢失,也只需要重构父RDD的部分分区即可
2-2、宽依赖:wide dependencies / shuffle dependencies
- 特点:会走shuffle
- 场景:如果RDD的分区数据会产生交叉:排序、分组、重新分区
- 一对多:一个父RDD的分区数据对应多个子RDD的分区数据