RDD 的概念和五大特性理解

RDD 概念

A Resilient Distributed Dataset (RDD), the basic abstraction in Spark. Represents an immutable,
partitioned collection of elements that can be operated on in parallel. 

RDD 是一个弹性分布式数据集 DataSet;

是一个抽象类;

表示一个可以进行并行操作的元素的不可变集合。

  • DataSet 可以理解成一个集合,集合里面存储了很多数据
  • Distributed 它的数据是分布式存储的,每个分区指向一个存储在内存或者硬盘中的数据块 (Block)
  • Resilient 弹性
    • 在面对出错情况(例如任意一台节点宕机)时,Spark 能通过 RDD 之间的依赖关系恢复任意出错的 RDD(如 B 和 D 可以算出最后的 RDD),RDD 就像一块海绵一样,无论怎么挤压,都像海绵一样完整;
    • 在经过转换算子处理时,RDD 中的分区数以及分区所在的位置随时都有可能改变。

不可变:不可变决定了它是只读的,所以 RDD 在经过变换产生新的 RDD 时,原有 RDD 不会改变。 只是会生成一个新的RDD

RDD 五大特性

Internally, each RDD is characterized by five main properties:
 *
 *  - A list of partitions
 *  - A function for computing each split
 *  - A list of dependencies on other RDDs
 *  - Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
 *  - Optionally, a list of preferred locations to compute each split on (e.g. block locations for
 *    an HDFS file)
  • 分区的集合;
  • 用来基于分区进行计算的函数(算子);
  • 依赖(与其他 RDD)的集合;
  • 对于键-值型的 RDD 的散列分区器(可选);
  • 对于用来计算出每个分区的地址集合(可选,如 HDFS 上的块存储的地址)。
  1. 一个分区的集合

    一个RDD有多个分区,一组分区列表。 后期spark任务是以RDD的分区为单位,一个分区对应一个task线程,spark任务最后是以task线程的方式运行在worker节点上的executor进程中

  2. 作用在每一个分区中的函数(算子)

    val rdd2 = rdd1.map(x => (x, 1))

  3. dependencies

    ​ 举例:RDD_1由 RDD_0 与转换(transform)函数(算子)转换而成,该算子其实是 RDD_0 内部成员。从这个角度上来说,RDD_1 依赖于 RDD_0,这种依赖关系集合也作为 RDD_1 的成员变量而保存。

    ​ Spark的容错机制跟这儿有很大关系

  4. 散列分区器(可选项)

    对于 kv类型的RDD才有分区函数 (必须产生shuffle) 如果不是kv类型的rdd,它的分区器就是None

    Spark中,有两种分区函数:

    1. HashPartitioner (默认分区器) 对key去hashcode值,然后对分区数取余得到分区号
    2. RangePartitioner 按照一定范围进行分区,相同范围的key会进入到同一个分区
  5. 用来计算每个分区的首选位置列表 (数据的本地性、数据的位置最优)

    spark任务的计算会优先考虑在存有数据的节点来开启计算任务。 减少数据的网络传输,提升性能

RDD算子分类

转换算子主要负责改变 RDD 中数据、切分 RDD 中数据、过滤掉某些数据等,并按照一定顺序组合。Spark 会将转换算子放入一个计算的有向无环图中,并不立刻执行,当 Driver 请求某些数据时,才会真正提交作业并触发计算,而行动算子就会触发 Driver 请求数据。这种机制与函数式编程思想的惰性求值类似。这样设计的原因首先是避免无谓的计算开销,更重要的是 Spark 可以了解所有执行的算子,从而设定并优化执行计划。

转换算子 (transform)

可以实现把一个RDD转换成一个新的RDD,它是延迟加载,并不会除非噶任务的真正运行

常见转换算子:

  • map
  • flatMap
  • reduceByKey
  • groupByKey
  • union

行动算子 (action)

行动算子从功能上来说作为一个触发器,会触发提交整个作业并开始执行。从代码上来说,它与转换算子的最大不同之处在于: ==转换算子返回的还是 RDD,行动算子返回的是非 RDD 类型的值,如整数,或者根本没有返回值

行动算子可以分为 Driver 和分布式两类。

  • Driver:这种算子返回值通常为 Driver 内部的内存变量,如 collect、count、countByKey 等。这种算子会在远端 Executor 执行计算完成后将结果数据传回 Driver。这种算子的缺点是,如果返回的数据太大,很容易会突破 Driver 内存限制,因此使用这种算子作为作业结束需要谨慎,主要还是用于调试与开发场景
  • 分布式:与前一类算子将结果回传到 Driver 不同,这类算子会在集群中的节点上“就地”分布式执行,如 saveAsTextFile。这是一种最常用的分布式行动算子。

特殊的行动算子,在计算过程中,用户可能会经常使用到同一份数据,此时就可以用到 Spark 缓存技术,也就是利用缓存算子将 RDD 进行缓存,从而加速 Spark 作业的执行速度。Spark 缓存算子也属于行动算子,也就是说会触发整个作业开始计算,想要缓存数据,你可以使用 cache 或者 persist 算子,它们是行动算子中仅有的两个返回值为 RDD 的算子。事实上,Spark 缓存技术是加速 Spark 作业执行的关键技术之一,尤其是在迭代计算的场景,效果非常好。

缓存需要尽可能地将数据放入内存。如果没有足够的内存,那么驻留在内存的当前数据就有可能被移除,例如 LRU 策略;如果数据量本身已经超过可用内存容量,这时由于磁盘会代替内存存储数据,性能会下降。

复制代码

def persist(newLevel: StorageLevel): this.type 
def cache(): this.type
def unpersist(blocking: Boolean = true): this.type

其中,cache() = persist(MEMORY_ONLY),Spark 在作业执行过程中会采用 LRU 策略来更新缓存,如果用户想要手动移除缓存的话,也可以采用 unpersist 算子手动释放缓存。其中 persist 可以选择存储级别,选项如下:

MEMORY_ONLY,

MEMORY_AND_DISK,

MEMORY_ONLY_SER,

DISK_ONLY,

MEMORT_ONLY_2,

MEMORY_AND_DISK2

内存足够大的话,肯定还是直接使用MEMORY_ONLY 因为内存肯定是最快的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值