【Spark教程】核心概念RDD

作者介绍:涂小刚,攻城狮一枚,有代码洁癖,热爱学习,热爱生活,痛恨酱油帝、跪舔帝。目前主要从事Spark大数据平台与机器学习平台相关方向的工作,关注Spark与TensorFlow

RDD全称叫做弹性分布式数据集(Resilient Distributed Datasets),它是一种分布式的内存抽象,表示一个只读的记录分区的集合,它只能通过其他RDD转换而创建,为此,RDD支持丰富的转换操作 ( 如: map, join, filter, groupBy 等),通过这种转换操作,新的RDD则包含了如何从其他RDDs衍生所必需的信息,所以说RDDs之间是有依赖关系的。

基于RDDs之间的依赖,RDDs会形成一个有向无环图DAG,该DAG描述了整个流式计算的流程,实际执行的时候,RDD是通过血缘关系(Lineage)一气呵成的,即使出现数据分区丢失,也可以通过血缘关系重建分区。

总结起来,基于RDD的流式计算任务可描述为:从稳定的物理存储(如分布式文件系统)中加载记录,记录被传入由一组确定性操作构成的DAG,然后写回稳定存储。另外RDD还可以将数据集缓存到内存中,使得在多个操作之间可以重用数据集,基于这个特点可以很方便地构建迭代型应用(图计算、机器学习等)或者交互式数据分析应用。

可以说Spark最初也就是实现RDD的一个分布式系统,后面通过不断发展壮大成为现在较为完善的大数据生态系统,简单来讲,Spark-RDD的关系类似于Hadoop-MapReduce关系。

RDD特点

RDD表示只读的分区的数据集,对RDD进行改动,只能通过RDD的转换操作,由一个RDD得到一个新的RDD,新的RDD包含了从其他RDD衍生所必需的信息。

RDDs之间存在依赖,RDD的执行是按照血缘关系延时计算的。如果血缘关系较长,可以通过持久化RDD来切断血缘关系。

分区

如下图所示,RDD逻辑上是分区的,每个分区的数据是抽象存在的,计算的时候会通过一个compute函数得到每个分区的数据。

如果RDD是通过已有的文件系统构建,则compute函数是读取指定文件系统中的数据,如果RDD是通过其他RDD转换而来,则compute函数是执行转换逻辑将其他RDD的数据进行转换。

只读

如下图所示,RDD是只读的,要想改变RDD中的数据,只能在现有的RDD基础上创建新的RDD。

由一个RDD转换到另一个RDD,可以通过丰富的操作算子实现,不再像MapReduce那样只能写map和reduce了,如下图所示。

RDD的操作算子包括两类,一类叫做transformations,它是用来将RDD进行转化,构建RDD的血缘关系;另一类叫做actions,它是用来触发RDD的计算,得到RDD的相关计算结果或者将RDD保存的文件系统中。下图是RDD所支持的操作算子列表。

依赖

RDDs通过操作算子进行转换,转换得到的新RDD包含了从其他RDDs衍生所必需的信息,RDDs之间维护着这种血缘关系,也称之为依赖。如下图所示,依赖包括两种,一种是窄依赖,RDDs之间分区是一一对应的,另一种是宽依赖,下游RDD的每个分区与上游RDD(也称之为父RDD)的每个分区都有关,是多对多的关系。

!

通过RDDs之间的这种依赖关系,一个任务流可以描述为DAG(有向无环图),如下图所示,在实际执行过程中宽依赖对应于Shuffle(图中的reduceByKey和join),窄依赖中的所有转换操作可以通过类似于管道的方式一气呵成执行(图中map和union可以一起执行)。

缓存

如果在应用程序中多次使用同一个RDD,可以将该RDD缓存起来,该RDD只有在第一次计算的时候会根据血缘关系得到分区的数据,在后续其他地方用到该RDD的时候,会直接从缓存处取而不用再根据血缘关系计算,这样就加速后期的重用。

如下图所示,RDD-1经过一系列的转换后得到RDD-n并保存到hdfs,RDD-1在这一过程中会有个中间结果,如果将其缓存到内存,那么在随后的RDD-1转换到RDD-m这一过程中,就不会计算其之前的RDD-0了。

Checkpoint

虽然RDD的血缘关系天然地可以实现容错,当RDD的某个分区数据失败或丢失,可以通过血缘关系重建。但是对于长时间迭代型应用来说,随着迭代的进行,RDDs之间的血缘关系会越来越长,一旦在后续迭代过程中出错,则需要通过非常长的血缘关系去重建,势必影响性能。

为此,RDD支持checkpoint将数据保存到持久化的存储中,这样就可以切断之前的血缘关系,因为checkpoint后的RDD不需要知道它的父RDDs了,它可以从checkpoint处拿到数据。

!

小结

总结起来,给定一个RDD我们至少可以知道如下几点信息:1、分区数以及分区方式;2、由父RDDs衍生而来的相关依赖信息;3、计算每个分区的数据,计算步骤为:1)如果被缓存,则从缓存中取的分区的数据;2)如果被Checkpoint,则从Checkpoint处恢复数据;3)根据血缘关系计算分区的数据。

编程模型

在Spark中,RDD被表示为对象,通过对象上的方法调用来对RDD进行转换。经过一系列的Transformations后,就可以调用Actions触发RDD的计算,Action可以是向应用程序返回结果( count, collect 等),或者是向存储系统保存数据( saveAsTextFile 等)。在Spark中,只有遇到Action,才会执行RDD的计算(即懒执行),这样在运行时可以通过管道的方式传输多个转换。

要使用Spark,开发者需要编写一个Driver程序,它被提交到集群以调度运行Worker,如下图所示。Driver中定义了一个或多个RDD,并调用RDD上的action,Worker则执行RDD分区计算任务。

应用举例

下面介绍一个简单的Spark应用程序实例WordCount,统计一个数据集中每个单词出现的次数,首先将从HDFS中加载数据得到原始RDD-0,其中每条记录为数据中的一行句子,经过一个flatMap操作,将一行句子切分为多个独立的词,得到RDD-1,再通过map操作将每个词映射为key-value形式,其中key为词本身,value为初始计数值1,得到RDD-2,将RDD-2中的所有记录归并,统计每个词的计数,得到RDD-3,最后将其保存到HDFS。


object WordCount {
  def main(args: Array[String]) {
    if (args.length < 2) {
      System.err.println("Usage: WordCount <inputfile> <outputfile>");
      System.exit(1);
    }
    val conf = new SparkConf().setAppName("WordCount")
    val sc = new SparkContext(conf)
    val result = sc.textFile(args(0))
                   .flatMap(line => line.split(" "))
                   .map(word => (word, 1))
                   .reduceByKey(_ + _)
    result.saveAsTextFile(args(1))
  }
}

结语

基于RDD实现的Spark相比于传统的Hadoop MapReduce有什么优势呢?总结起来应该至少有三点:

1)RDD提供了丰富的操作算子,不再是只有map和reduce两个操作了,对于描述应用程序来说更加方便;

2)通过RDDs之间的转换构建DAG,中间结果不用落地;

3)RDD支持缓存,可以在内存中快速完成计算。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏简单聊聊Spark

Spark性能调优篇一之任务提交参数调整

最近在做spark的项目,虽然项目基本功能都实现了,但是在真正的成产环境中去运行,发现程序运行效率异常缓慢;迫于无奈(实际是自己都不忍直视了),所以决定对程序做...

732
来自专栏hadoop学习

hadoop需要哪些技术支持

hadoop是一个开源软件框架,可安装在一个商用机器集群中,使机器可彼此通信并协同工作,以高度分布式的方式共同存储和处理大量数据。最初,Hadoop 包含以下两...

1023
来自专栏祝威廉

Spark Streaming 数据产生与导入相关的内存分析

我这篇文章会分几个点来描述Spark Streaming 的Receiver在内存方面的表现。

733
来自专栏涤生的博客

服务框架的技术栈

随着业务规模的扩张,为了满足业务对技术的要求,技术架构需要从单体应用架构升级到分布式服务架构,来降低公司的技术成本,更好的适应业务的发展。分布式服务架构的诸多优...

932
来自专栏人工智能

使用Apache Spark的微服务的实时性能分析和分析

作为一种架构风格,微服务因其极高的灵活性,越来越受欢迎。应用程序在功能上分解为一组松散耦合的协作服务,通过定义良好的(REST)API进行交互。通过采用这些设计...

2245
来自专栏CSDN技术头条

变不可能为可能,Tachyon帮助Spark变小时级任务到秒

本文作者是Gianmario Spacagna和Harry Powell,Barclays的数据科学家。 集群计算和大数据技术已经取得了很多进展,不过现在很多大...

1798
来自专栏Java学习网

Java线程使用技巧学习(二)

Java线程使用技巧学习(二)  进阶篇   3.线程本地存储   这个和前面提到的两个略有不同。ThreadLocal是在Thread类之外实现的一个功能...

18610
来自专栏美图数据技术团队

Hello Spark! | Spark,从入门到精通

Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架,是专为大规模数据处理而设计的快速通用的大数...

940
来自专栏最高权限比特流

漫谈计算机组成原理(二)系统总线

从引言中,我们基本上能够了解到总线在计算机系统中的作用。但是上面的说法只是一个概论,我们需要给出更加详细的总线的作用:总线是计算机中各个部件的信息传输线。在计算...

1613
来自专栏進无尽的文章

多线程-概述及底层实现机制浅析

在打算写这篇多线层底层实现机制的时候,突然发现自己对于计算机竟然懂得这么表面,对于CPU的工作原理都不完全清楚,于是又转头查看了一些CPU相关的资料。也不敢钻的...

741

扫码关注云+社区