Spark RDD:弹性分布式数据集

时间:2021-12-15 06:10:01
  1. RDD是只读的、分区记录的集合
  2. 一个RDD的生成只有两种途径:
    • 基于内存集合或稳定物理存储中的数据集执行确定性操作
    • 通过在已有的RDD上执行转换操作
  3. RDD具有自动容错、位置感知和可伸缩性特点
  4. RDD不需要物化,RDD通过Lineage来重建丢失的分区:一个RDD中包含了如何从其他RDD衍生所必须的相关信息,从而不需要检查点就可以重构丢失的数据分区
  5. RDD只支持粗粒度转换,即一个操作会被应用在RDD的所有数据上
  6. RDD包含
    • partition:分区,一个RDD会有一个或多个分区
    • preferredLocations(p):根据分区p存放的位置,返回在哪个节点访问更快
    • dependencies():RDD的依赖关系
    • compute(p, context):对于分区p而言,进行迭代计算
    • partitioner():RDD的分区函数,该属性只存在于(K、V)类型的RDD中,对于非(K、V)类型的partitioner的值就是None;partitioner()决定了RDD本身的分区数量,也可作为其父RDD Shuffle 输出中每个分区进行数据切割的依据

RDD分区

  1. 程序员还可以从两个方面控制RDD,即持久化和分区。用户可以请求将RDD缓存,这样运行时将已经计算好的RDD分区存储起来,以加速后期的重用。缓存的RDD一般存储在内存中,但如果内存不够,可以写到磁盘上
  2. RDD还允许用户根据关键字(key)指定分区顺序,这是一个可选的功能。目前支持哈希分区和范围分区。分区的多少涉及对这个RDD进行并行计算的粒度,因为每一个分区的计算都在一个单独的任务上执行
  3. 通过备份任务的拷贝,RDD还可以处理落后任务(即运行很慢的节点)
  4. 与DSM(分布式共享内存)相比,RDD有两个好处:
    • 对于RDD中的批量操作,运行时将根据数据存放的位置来调度任务,从而提高性能
    • 对于基于扫描的操作,如果内存不足以缓存整个RDD,就进行部分缓存。把内存放不下的分区存储到磁盘上,此时性能与现有的数据流系统差不多
  5. 当然也可以在创建RDD的时候不指定分区,这时就采用默认的分区数,即程序所分配到的资源的CPU核的个数

RDD的优先位置

  1. RDD优先位置属性与Spark中的调度相关,返回的是此RDD的每个partition所存储的位置,按照“移动数据不如移动计算”的理念,在Spark进行任务调度的时候,尽可能地将任务分配到数据块所存储的位置(如果一个partition对应的数据块存储了多份,也会返回多份地址)

RDD依赖关系

  1. 在Spark中,存在两种类型的依赖:
    • 窄依赖:每一个父RDD的分区至多只被子RDD的一个分区所使用
    • 宽依赖:每一个父RDD的分区会被子RDD的多个分区所使用
  2. 窄依赖和宽依赖的区别:
    • 窄依赖可以在集群的一个节点上如流水线一般地执行,可以计算所有父RDD的分区,相反的,宽依赖需要取得父RDD所有分区上的数据进行计算,将会执行MapReduce一样的shuffle操作
    • 对于窄依赖来说,节点计算失败后的恢复会更加有效,相反的,在有宽依赖的继承关系中,一个节点的失败将会导致其父RDD的多个分区重新计算,代价非常高