文章目录
前言
在前面的博客《深入理解Spark》 深入探讨了Spark架构原理内容,该文提到Stage的划分,为什么要做Stage划分?是为了得到更小的Task计算单元,分发给Executor的线程运行,将规模庞大、多流程的计算任务划分为有序的小颗粒的计算单元,实现更高效的计算。那么Stage划分怎么实现?需依赖RDD(Resilient Distributed Datasets,弹性分布式数据集),可以说,RDD是Spark最为核心的概念。本文内容部分参考了《弹性式数据集RDDs》以及《Spark官方文档》
1、RDD简介
RDD 是分布式的、可容错的、只读的、分区记录的弹性数据集合(在开发角度来看,它是一种数据结构,并是绑定了多个方法和属性的一种object),支持并行操作,可以由外部数据集或其他 RDD 转换而来,细读Resilient Distributed Dataset这三个单词,更深层的含义如下:
- Resilient: 弹性的,RDD如何体现出弹性呢?通过使用RDD血缘关系图——DAG,在丢失节点上重新计算上,弹性容错。
- Distributed:分布式的,RDD的数据集驻留在多个节点的内存中或者磁盘上(一分多)。
- Dataset: 在物理文件存储的数据
更具体的说明:
-
一个 RDD 由一个或者多个分区(Partitions)组成。对于 RDD 来说,每个分区会被一个计算任务所处理,用户可以在创建 RDD 时指定其分区个数,如果没有指定,则默认采用程序所分配到的 CPU 的核心数。
(这一特点体现出RDD的分布式,RDD的分区是在多个节点上指定的,注意不是指把master分区拷贝到其他节点上,spark强调的是”移动数据不如移动计算“,避免跨节点拷贝分区数据。做这样假设:RDD如果不设计为多个分区,那么一个RDD就是代表一个超大数据集,而且只能在单机行运行,这跟Pandas的DataFrame区别就不大了。) -
Spark一个计算程序,往往会产生多个RDD,这些RDD会保存彼此间的依赖关系,RDD 的每次转换都会生成一个新的依赖关系,这种 RDD 之间的依赖关系就像流水线一样。在部分分区数据丢失后,可以通过这种依赖关系重新计算丢失的分区数据,而不是对 RDD 的所有分区进行重新计算。
(这个特点就体现了RDD可恢复性,) -
Key-Value 型的 RDD 还拥有 Partitioner(分区器),用于决定数据被存储在哪个分区中,目前 Spark 中支持 HashPartitioner(按照哈希分区) 和 RangeParationer(按照范围进行分区)。
(其实很多中间件或者组件只要涉及到Partition,必然少不了使用Partitioner(分区器),例如kafka的partition,Producer可通过对消息key取余将消息写入到不同副本分区上,例如redis的key在slot上分配,也是通过对key取余。) -
一个优先位置列表 (可选),用于存储每个分区的优先位置 (prefered