Spark论文研究之-一篇文章彻底弄清RDD

本文详细探讨了Spark中的弹性分布式数据集(RDD)的概念,包括其作为只读、分区记录集合的特性,以及如何通过转换操作创建和容错机制。RDD通过谱系图实现故障恢复,无需数据复制,只需重新计算丢失分区。Spark编程接口以Scala为基础,通过transformations和actions操作RDD,实现懒计算和数据持久化。RDD的优势在于其批量操作、不可变性和高效的内存管理,适用于并行计算和迭代算法,但在特定场景下可能不适用。文章还涵盖了Spark的实现、调度、内存管理和检查点机制,以及其在大数据处理、机器学习和交互式查询中的性能优势。
摘要由CSDN通过智能技术生成

2.2 RDD抽象

2.2.1 RDD说明

  • RDD是啥?
      形式上,RDD是一种只读的分区记录集合。是一种具有容错能力的并行数据结构。使用户可以显式地将数据存在磁盘上或是内存中,控制其分区,并使用丰富的运算符来操作数据。

  • RDD怎么产生?
      只能通过两种方式产生:确切的讲只能通过RDD 转换操作产生

    • 确定的操作作用于稳定存储的数据上
    • 确定的操作作用于其他RDD
  • RDD产生动机?
      在上一篇文章中已经提到,Spark研究者发现现有的处理系统其最大的共性问题是数据不能高效共享(利用外部存储来进行数据共享),有些系统即使在这方面做了优化,但也只支持特定的模式。

  • 一般的内存存储抽象是怎么容错的?
      跨节点复制数据或者通过日志来记录跨节点的更新,然而这种方式对于数据敏感性的应用来说是昂贵的,一方面这需要再集群网络上大量复制数据,而其带宽又远小于RAM,另一方面,这又占用了大量的存储空间。

  • RDD是怎么容错的?
      RDD提供了基于粗粒度的转换接口,能够将相同的运算操作应用到大量数据记录上。于是,只需要记录产生RDD的转换即可,也就是官方所说的lineage,而不需要记录实际数据。这样一来,每当有分区丢失的时候,RDD有记录足够的关于它是从哪些RDD计算得来的信息,然后据此重新计算丢失分区即可。

  • 其他
      RDD有足够的信息来说明它是如何从其他数据集(其谱系)派生的,以便从稳定存储中的数据计算其分区。这是一个强大的属性:实质上,程序不能引用在失败后无法重建的RDD。
      用户可以控制RDD的其他两个方面:持久化和分区。用户可根据将来的使用需要为RDD选择一种存储策略(eg:是存在内存还是存在磁盘),用户还可以依据每个记录中的key值对RDD的元素进行跨机器分区。

2.2.2 Spark编程接口

  Spark通过类似于DryadLINQ和FlumeJava的语言集成API来公开其RDD(用户可用),其中每个RDD都被当做一个对象,并利用这个对象的方法调用转换。
  Spark的方法分为两种,一种为transformations(eg: map 、filter),另外一种为actions(eg:count、collect、save)。用户通常可以通过transformations操作从稳定的存储数据中创建RDD,然后可以在action中使用这些数据集。跟DryadLINQ一样,Spark对RDDs执行懒计算,也就是说只有当第一次遇到要使用RDDs的情况下(action操作)Spark才开始执行RDDs计算。因此,Spark可以对所有transformations进行管道处理。
  在预料到某个RDD在将来会被再使用的情况下,Spark提供了persist接口来持久化该RDD,默认情况下Spark将持久化的RDD保存在内存中,在RAM不够的情况下会溢出到磁盘。spark提供了不同的持久化策略,用户可以选择是仅仅持久化到磁盘上,或者对持久化RDD进行跨机器复制。这些都通过persist的flag来完成。除此以外,用户还可以选择持久化优先级,以此来决定存储到内存的RDDs应该最先溢出到磁盘。
  
  下面来看看spark api是怎么使用的以及模型是怎么容错的

lines = spark.textFile("hdfs://...")
errors = lines.filter(_.startsWith("ERROR"))
errors.persist()

注意第三行,这一操作使errors被持久化到内存中,后续查询就可共享该数据。另外还需要注意的是直到这里,Spark还没有任何工作开始运行。通过执行一个action操作例如errors.count()后,用户便可以使用该RDD。通过将errors的分区保存在内存中,大大加速了后续基于此RDDs的计算。
RDD谱系图

图2.1 RDD谱系图(沿袭图)



  在这个例子中,Spark 调度器会把后两步转换进行一个组合成一个管道。然后发送一组任务到缓存有errors分区的节点来计算该转换。如果errors的一个分区丢失,spark会将filter(_.startsWith(“ERROR”))仅仅应用到相应的lines的分区上来重计算丢失分区。

2.2.3 RDD模型的优势

RDDs和分布式共享内存的比较
        图 3.1 RDDs和分布式共享内存的对比


1、可以看到,RDD和DST之间主要的不同在于,RDD只能通过粗粒度的转换方式来创建。而DST允许在内存的任意位置读写。这将RDD限制为执行批量写入的程序,但这也允许更高效的容错。RDD利用谱系图来进行故障恢复,不会带来检查点开销。而且,只有丢失的分区需要被重新计算,重计算任务也可以多节点并行执行,无需回滚程序。
2、RDD的第二个益处在于它的不可变特性,这种特性使得可以运行处理缓慢节点的任务的备份来缓解节点任务执行落后的状况。
3、相对于DSM,RDD还有另外两方面的好处。首先,在RDD的批量操作中,在运行时可以根据数据位置来调度任务以提高性能。然后,在RDD用于扫描操作的时候,RDD可以优雅的降级,也就是在内存不够的情况下,会溢出到磁盘。

2.2.4 不适合RDDs的应用


  首先需要明确的是,RDD的目标是批处理应用,也就是将同一个操作应用到一个数据集的每个元素上。在这样的情况下,RDD才能将每一个转换操作作为执行谱系图中的一个步骤有效的记录下来。以便于在恢复丢失分区时不需要记录庞大的数据信息。所以,RDD并不是适合进行异步细粒度更新的应用程序,比如,web应用的存储系统或者是网络爬虫程序。


2.3 Spark编程接口


1、为什么选择scala来编写spark?

  官方解释:因为scala是简洁性(体现在交互上的便利性)和高效性(静态类型)的结合。
2、怎么使用?
  开发者使用driver(驱动程序)连接到集群workers(工作程序),driver定义RDD并且在其上调用action。driver上的spark代码也追踪RDD沿袭。workers是长期存在的进程,可以跨操作在RAM中存储分区。
  用户给RDD操作如map提供参数,通过传入闭包。Scala将每个闭包视为一个java Object,这些对象可以被序列化并可以被加载到另一个节点上以便于把闭包在网络间传输。Scala也将跟闭包绑定的任何变量当做域保存在java Object中。
  RDD是由其元素类型参数化的静态类型对象。eg:RDD[int]表示integer类型的RDD,但是,由于Scala的类型推断特性,一般情况下我们都将类型省略。
  尽管用scala把RDD公开的方法的概念是简单的,但是挑战是通过反射的方式处理Scala闭包对象所带来的问题。而且,让Scala解释器可以使用spark也需要做很多工作。

2.3.1 Spark中的RDD操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值