什么是 RDD ?
弹性分布式数据集,是 Spark 中最基本的数据处理模型。代码中是一个抽象类,它代表一个弹性的、不可变、可分区、里面的元素可并行计算的集合;
特性:
- 弹性:
存储弹性:内存与磁盘的自动切换;
容错弹性:数据丢失可以自动恢复;
计算弹性:计算出错有重试机制;
分片弹性:可根据需要重新分片; - 分布式:数据存储在大数据集群不同节点上;
- 数据集:RDD 封装了计算逻辑,并不保存数据;
- 数据抽象:RDD 是一个抽象类,需要子类具体实现;
- 不可变:RDD 封装了计算逻辑,是不可改变的,想要改变,只能产生新的 RDD,在新的 RDD 里面封装计算逻辑;
- 可分区、并行计算:对读取进来的数据进行分区,之后将不同分区的数据发送给不同的 Executor 来处理;
工作原理
1、启动 Yarn 集群;
2、Spark 通过申请资源创建调度节点和计算节点;
3、Spark 根据需求将计算逻辑根据分区划分成不同的任务;
4、调度节点将任务根据计算节点状态发送到对应的计算节点进行计算;
从以上流程可以看出 RDD 在整个流程中主要用于将逻辑进行封装,并生成 Task 发送给 Executor 节点执行计算;
RDD 依赖关系
RDD 血缘关系
Spark 的所有算子都是基于 RDD 来执行的,不通的场景会有不同的 RDD 实现类,但是都可以进行相互转换。RDD 在执行过程中会生成 DAG 图,然后形成 Lineage(血统),RDD 的 Lineage 会记录 RDD 的元数据和转换行为,当该 RDD 的部分分区数据丢失时,它可以根据这些信息来重新运算和恢复丢失的数据分区,保证容错性;
依赖关系
两个相邻 RDD 之间的关系;
窄依赖
指父 RDD 的每个分区只能被一个子 RDD 分区使用,子 RDD 分区通常对应常数个父 RDD 分区;
例如:map()、filter()、union()、join() 等操作都会产生窄依赖;
为什么设计窄依赖?
窄依赖的多个分区可以并行计算;
窄依赖如果丢失一个分区的数据,只需要重新计算对应的分区数据;
宽依赖
即 shuffle 依赖,指父 RDD 的每个分区都可能被多个子 RDD 分区使用,子 RDD 分区通常对应所有的父 RDD 分区;
例如:groupByKey()、reduceByKey()、sortByKey() 等操作都会产生宽依赖;
为什么设计宽依赖?
划分 Stage 的依据,对于宽依赖,必须等到上一阶段的计算完成才能计算下一阶段;
RDD 的缺陷
- 不支持细粒度的写和更新操作:Spark写数据是粗粒度的,所谓粗粒度就是批量写入数据,目的是为了提高效率,但是Spark读数据是细粒度的,也就是一条一条读;
- 不支持增量迭代计算;