RDD基础概念

一个适用与分布式计算的数据抽象,一个弹性分布式的数据集

RDD数据的概念来自与一篇论文

RDD(弹性分布式数据集,Resilient Distributed Dataset)是 Apache Spark 的基本数据结构。RDD 是一个分布式的、不可变数据集合,允许用户在集群的多个节点上并行操作数据。这种设计使得 RDD 特别适合于大规模数据处理的并行计算任务。以下是关于 RDD 的一些基础概念和特点:

1. 弹性性质

  • 容错性:RDD 的“弹性”主要体现在其容错机制上。如果RDD的任何分区遭受故障,它可以通过原始创建操作的行动记录(称为血统 lineage)自动重建。
  • 可恢复:通过利用其血统信息,RDD 可以对失败的节点中的数据进行重新计算,而不是通过数据复制来提供容错能力。

2. 分布式特性

  • 分区数据:RDD 数据被分割成多个分区,这些分区可以在集群的不同节点上并行处理。
  • 位置透明:用户不需要知道数据具体存储在哪里,Spark 负责数据的分布和处理的调度。

3. 不可变性

  • 只读:一旦创建,RDD 的数据就不可更改。所有对数据的操作都会生成一个新的 RDD,原始 RDD 保持不变。
  • 操作结果的确定性:同一个 RDD 上执行相同的操作,无论执行多少次,结果都是相同的。

4. 类型安全

  • 泛型支持:RDD 是一个泛型类型,支持存储任何类型的对象,包括用户定义的类。

5. 创建和转换

  • 并行集合:通过在 SparkContext 上调用 parallelize 方法,可以将现有集合(如数组或列表)转换为 RDD。
  • 外部数据集:通过 SparkContext 上的方法,如 textFile,可以从外部存储(如 HDFS、S3 等)读取数据并创建 RDD。
  • 转换操作:例如 mapfilterreduceByKey 等,用于生成新的 RDD。

6. 惰性求值

  • 转换的惰性执行:在 RDD 上定义的转换操作不会立即执行。只有在触发行动(如 countcollect)时,所有之前定义的转换才会被计算。

7. 行动操作

  • 触发计算:行动操作(如 collectcountsaveAsTextFile)用于触发实际计算,并在需要时从 RDD 中提取结果或将结果存储到外部系统。

8. 存储特性

  • 内存:RDD 默认存储在内存中,这有助于快速访问和处理。将数据保留在内存中,可以显著提高迭代算法和交互式查询的性能。通过 cache() 或 persist() 方法,可以将 RDD 持久化到内存中。这是在进行多次操作时避免重新读取数据的有效方法。
  • 外存:磁盘存储:当内存资源有限或处理非常大的数据集时,可以选择将 RDD 持久化到磁盘

RDD五大特性

1. 分区性

  • RDD的分区是RDD数据存储最小单位,一份RDD的数据,本质是分隔成了多个分区

  • RDD是逻辑上的抽象对象,而[[1, 2, 3], [4, 5, 6], [7, 8, 9]]是物理分区

  • 示例

    >>> rdd = sc.parallelize([1,2,3,4,5,6,7,8,9],3)
    >>> rdd.glom().collect()
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]                                               
    >>>
    
    >>> rdd = sc.parallelize([1,2,3,4,5,6,7,8,9],6)
    >>> rdd.glom().collect()
    [[1], [2, 3], [4], [5, 6], [7], [8, 9]]
    >>> 
    

2. RDD方法会作用在其所有的分区上

>>> rdd = sc.parallelize([1,2,3,4,5,6,7,8,9],3)
>>> rdd.map(lambda x:x*10).glom().collect()
[[10, 20, 30], [40, 50, 60], [70, 80, 90]]   

RDD方法大致原理

3. RDD血缘性

  • RDD之间是有依赖关系(RDD有血缘关系)
  • 可以叫做RDD的迭代计算关系
from pyspark import SparkConf, SparkContext
if __name__ == '__main__':

    conf = SparkConf().setAppName("WordCountHelloWorld")

    sc = SparkContext(conf=conf)

    # 读取 HDFS 上的文件
    rdd1 = sc.textFile('hdfs://mycluster/sparkdata/words.txt')

    # 将每一行按空格拆分成单词
    rdd2 = rdd1.flatMap(lambda line: line.split())

    # 每个单词计数为 1
    rdd3 = rdd2.map(lambda word: (word, 1))

    # 对相同的单词进行计数
    rdd4 = rdd3.reduceByKey(lambda x, y: x + y)

    # 输出结果
    print(rdd4.collect())

RDD血缘性

4. Key-Value型的RDD可以有分区器

key-Value型指的是RDD的最基本的数据构成为一个二元元组 例如('key','value')

  • 分区规则:

    • 默认分区器:Hash分区规则,可以手动设置一个分区器(rdd.partitionBy的方法设置)
  • 特性的可选型:

    • 这个特性是可选的,不是所有的RDD都是Key-Value型

5. RDD的分区规划,会尽量靠近所在的服务器

计算向数据靠拢

在初始RDD(读取数据的时候)规划的时候,分区会尽量规划到存储数据所在节点的上。

  • 优点:
    • 避免网络读取而带来的延迟

Spark是尽量将计算靠拢数据,并不是100%的,原因是因为如果只有3台节点有数据,但是需要4个Executor来进行计算