Spark基础(二)RDD简介

参考文章
Spark学习之路 (三)Spark之RDD

从MR到RDD

1、 在MR的计算中,每次的map与reduce完成后都需要写入到磁盘中,所需的时间较长,增加了整体计算的时间。

2、在Hive出现后直接的数据存储已经解决。可以方便的通过SQL进行数据的读取操作,但是计算本身依然依赖于MR。依然没有解决落盘所需时间较长的问题。

3、Spark出现,支持将数据自定义为可以拓展的RDD格式,Spark使用内存进行计算,运算速度比MR不知道高到哪里去了。

RDD的简介

RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。RDD具有数据流模型的特点:

  • 自动容错
  • 位置感知性调度
  • 可伸缩性

RDD允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。

RDD的属性

(1)一组分片(Partition),即数据集的基本组成单位。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建RDD时指定RDD的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的CPU Core的数目。

(2)作用于RDD的计算函数。Spark中RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。

(3)RDD之间的依赖关系。RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD的所有分区进行重新计算。

(4)一个Partitioner,即RDD的分片函数。当前Spark中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于于key-value的RDD,才会有Partitioner,非key-value的RDD的Parititioner的值是None。Partitioner函数不但决定了RDD本身的分片数量,也决定了parent RDD Shuffle输出时的分片数量。

(5)一个列表,存储存取每个Partition的优先位置(preferred location)。对于一个HDFS文件来说,这个列表保存的就是每个Partition所在的块的位置。按照“移动数据不如移动计算”的理念,Spark在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置,尽量避免数据的移动。

RDD的弹性

  1. 自动进行内存和磁盘数据存储的切换
    Spark优先把数据放到内存中,如果内存放不下,就会放到磁盘里面,程序进行自动的存储切换
  2. 基于血统的高效容错机制
    在RDD进行转换和动作的时候,会形成RDD的Lineage依赖链,当某一个RDD失效的时候,可以通过重新计算上游的RDD来重新生成丢失的RDD数据。
  3. Task如果失败会自动进行特定次数的重试
    RDD的计算任务如果运行失败,会自动进行任务的重新计算,默认次数是4次。
  4. Stage如果失败会自动进行特定次数的重试
    如果Job的某个Stage阶段计算失败,框架也会自动进行任务的重新计算,默认次数也是4次。
  5. Checkpoint和Persist可主动或被动触发
    RDD可以通过Persist持久化将RDD缓存到内存或者磁盘,当再次用到该RDD时直接读取就行。也可以将RDD进行检查点,检查点会将数据存储在HDFS中,该RDD的所有父RDD依赖都会被移除。
  6. 数据调度弹性
    Spark把这个JOB执行模型抽象为通用的有向无环图DAG,可以将多Stage的任务串联或并行执行,调度引擎自动处理Stage的失败以及Task的失败。
  7. 数据分片的高度弹性
    可以根据业务的特征,动态调整数据分片的个数,提升整体的应用执行效率。

RDD的特点

分区

只读

依赖: 分为宽依赖与窄依赖。

  • 宽依赖中,父RDD的分区数据去往了子RDD的不同分区。实际是产生了shuffle。
  • 窄依赖中,父RDD的分区数据去往了子RDD的一个分区,叫做窄依赖。实际没有产生任何shuffle过程。

checkpoint: 持久化,对于常用的RDD可以进行持久化。

RDD的算子

Action

对rdd结果计算后返回一个数值value给驱动程序

Transformation

根据数据集创建一个新的数据集,计算后返回一个新RDD;例如:一个rdd进行map操作后生了一个新的rdd。

RDD的血统

根据RDD的依赖与产生的顺序得到的数据。RDD的血统会记录下RDD的元数据转换信息,当某个分区的数据丢失时,他可以根据这些信息来重新运算和恢复丢失的数据分区。

RDD的缓存

Spark可以再内存中持久化合作和缓存数据集。当持久化某个RDD时,每个节点都把分区结果保存在内中,当后续的运算中用到这个RDD时,可以直接从缓存中获取。更加迅速。

RDD的缓存方式

Persist

可以指定几种缓存方式
1、缓存到磁盘或者内存
2、缓存到磁盘 + 内存

Cache

只缓存到内存

RDD的DAG生成与shuffle过程

DAG

有向无环图,根据RDD之间的依赖关系来生成的。

stage的划分

从前向后划分,遇到窄依赖划分到同一个stage,遇到宽依赖*(shuffle)时候从新创建一个新的stage。

ShuffleManager

在spark1.2之前,使用的shuffle类叫做HashShuffleManger,通过这种方法会产生大量的中间结果小文件,影响性能。

在1.2版本之后,使用SortShuffleManager来替代了HashShuffleManger。SortShuffleManager中会将小文件进行合并。在后代的RDD来进行数据的拉取的时候会找到合并文件中自己所需要的的内容进行拉取。

SortShuffleManager包含了两种机制,普通机制与bypass机制

SortShuffleManager中的普通机制

在这里插入图片描述

数据会先写入一个内存数据结构中(默认5M),此时根据不同的shuffle算子,可能选用不同的数据结构。如果是reduceByKey这种聚合类的shuffle算子,那么会选用Map数据结构,一边通过Map进行聚合,一边写入内存;如果是join这种普通的shuffle算子,那么会选用Array数据结构,直接写入内存。

总结下来,总体过程为

  1. 排序:
  2. 溢写:
  3. Merge: 一个task将所有数据写入内存数据结构的过程中,会发生多次磁盘溢写操作,也就会产生多个临时文件。最后会将之前所有的临时磁盘文件都进行合并。由于一个task就只对应一个磁盘文件,也就意味着该task为Reduce端的stage的task准备的数据都在这一个文件中,因此还会单独写一份索引文件,其中标识了下游各个task的数据在文件中的start offset与end offset。

SortShuffleManager中的bypass机制

在这里插入图片描述

当分区的task数量小于等于spark.shuffle.sort.bypassMergeThreshold参数的值时(默认为200)就会启动bypass机制。相对于普通机制省略了sort机制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值