分布式弹性数据集(RDD)是一个不可变型分布式对象集合,这些元素分布在集群中的多个节点上。RDD是Spark中使用的基本对象。他们是不可变型集合,用于表示数据,并且内置了可靠性以及故障恢复能力。
Spark RDD是弹性的,并具备容错能力,它使得Spark能在出现故障时恢复RDD。不可变性使得RDD一旦被创建就是只读的。可对RDD进行转换从而创建新的RDD,但原始RDD在原始RDD在创建后永远都不会被修改的。这使得RDD能不受争用和其他同步问题的影响。
RDD的分布式天性则是由于RDD只包含数据的一个引用,而实际数据则以分区形式存储在集群中的节点上。
RDD实质上是一个数据集,被分区到哦集群中的多个节点上,这些分区可来自HDFS、HBase表、Cassandra表或Amazon S3。
从内部讲,每个RDD具备如下五个主要特征:
- 是一个分区的列表;
- 是一个对每个分片都进行计算的函数;
- 基于其他RDD的一个依赖列表;
- 有时,是一个健指型RDD的分区器(例如,可以说RDD是hash分区的)
- 有时,是一个计算每个分片的优先位置列表(例如,一个HDFS文件的块地址)
driver在RDD对象视为分布式数据的句柄。这类似于使用了一个指向数据的指针,而不是直接使用真实数据;只有在需要时,才访问真实数据。
默认情况下,RDD使用hash分区器在集群内对数据进行分区。其分区个数与集群中的节点个数无关。因此经常发生集群中的一个节点上分布了多个分区的数据这样的情况。现有数据的分区个数取决于集群中的节点数量和数据量。worker节点上的任务处理的数据主要来自本地节点,或部分来自远程节点。这称为数据的本地化,执行任务时会尽可能选择本地数据。
数据本地化会严重影响任务的性能。数据本地化的默认选择顺序为:进程本地化>节点本地化>无首选位置>机架本地化>跨机架
并不能保证一个节点可获取多个分区,这会影响executor的处理效率,因为如果一个节点上有太多分区,那么处理这些分区的时间就会变长,会让executor上的Spark core过载,从而减缓该阶段的处理速度,进而影响整个作业的执行效率。所以数据的分区问题,是提升Spark作业性能的关键。
创建RDD
无论RDD是如何创建的,初始的RDD都被称为基础RDD,使用各种操作创建的后续RDD都是该RDD的血统。这是RDD实现容错能力和恢复能力的秘诀。
RDD可基于任意的transformation或action算子来产生新的RDD。RDD也会存储其血统机制,从而用于从故障中进行恢复。
RDD创建方式:
- 并行处理集合
- 从现有数据源中读取数据
- 对现有RDD进行转换
- streamingAPI
并行处理集合
并行处理集合可通过在集合上调用parallelize()来实现,这是在driver程序内部完成的。当driver尝试并行处理集合时,会讲集合拆分为分区,并将数据分区分布到集群中。
从现有数据源中读取数据
从现有的分布式数据(如Amazon S3、Cassandra和HDFS等)读取数据。
从现有RDD进行转换
RDD天然是不可变型。因此可以对RDD应用transformation算子来创建新的RDD。filter就是一种典型的transformation算子。
Streaming API
通过Streaming API创建的RDD被称为离散化流式RDD。