Spark论文思想之-基于RDD构建的模型(Shark的来龙去脉)

3.1 介绍

首先RDD提供以下功能:

  • 跨集群的不可变存储(在Spark中,记录是指Java Object)
  • 使用键对数据进行分区控制
  • 考虑分区的粗粒度运算符
  • 由于是内存计算,所以低延迟

3.2 在RDD上实现其它模型的技术

  在专业引擎里,不只是数据运算符,而且存储格式、甚至访问方法都被优化了。如SQL引擎Shark是以面向列的格式处理数据,同时一个图计算引擎如GraphX在数据被创建索引的情况下性能更高。我们讨论使用RDD实现这些优化的常见方法,利用RDD的容错和组合优势,同时保持和专业系统匹敌的性能。

3.2.1 在RDD中的数据格式

  尽管RDD存储简单、扁平化的数据,实现更丰富的存储格式的一个有效途径是在一个RDD记录中存储多个数据项,从而在每个记录中实现更复杂的存储。以这种方式批量处理几千条记录足以实现专用数据结构的大部分效率,同时仍将每个RDD记录保持在几兆字节大小。
  例如,在分析数据库中,一个通用的优化方式是面向列存储和压缩。在Shark系统中,我们将多个数据库记录保存在一个Shark记录中,并应用这种优化。一个有10000到100000个记录的批的压缩程度非常接近于以面向列的格式存储整个数据库,以至于我们仍然有显著的优势。一个高级的例子,GraphX需要对表示图的顶点和边的数据集执行非常稀疏的join。它通过在每个RDD记录中存储一个包含多个图记录的哈希表来实现这一点,从而在与新的数据join的时候能够快速找到特定的顶点和边。这点在图计算算法中很重要,在最后几次迭代中只有很少的顶点和边处于active状态,但是他们仍然需要和整个数据集进行join。这一机制能被用于Spark Streaming 的updateStateByKey的更有效地实现。
  RDD的两方面的原因使得这种方式很高效。首先,RDD常见于内存中,指针能够被用于仅仅读取和每个操作相关的那部分记录。例如一组面向列的(Int , Float)记录的表示能够实现为一个Int数组和一个Float数组。如果我们只想读Int那一列,我们就可以把指针移到该列,从而避免扫描内存中的Float列。同样地,在上面哈希表的RDD中,我们可以只扫描我们需要的record。
  其次,一个问题可能是,在每个计算模型都有其自己的批处理记录表示的情况下,如何有效地组合处理类型。幸运的是,RDD的低级别的接口是基于迭代器的,这使得不同的格式之间可以快速地、流水线式的进行转换。包含复合记录的RDD可以通过批处理上的flatMap操作有效地在解压缩的记录上返回一个迭代器。这可以和对解压记录的进一步窄依赖转换操作、或者是把记录打包成另一种格式的转换操作进行pipeline组合处理,减少解压数据的传输量。迭代器对内存数据是一种有效的接口,因为他们典型地用来执行扫描。只要每个批处理记录适合CPU缓存,迭代器就能够快速地执行转换。

3.2.2 数据分区

  专业模型中第二个常见的优化是以特定于域的方式跨集群分区数据以加速应用。例如,Pregel
和HaLoop使用用户自定义函数来保持分区,加速数据集的join。并行数据库通常也提供各种形式的分区。使用RDD,分区可以通过每个记录的键被轻松实现(事实上,这是RDD记录中的唯一结构概念)。注意,尽管key用于整个记录,匹配多个基础数据项的组合记录依然具有有意义的键。例如在GraphX中,每个分区记录具有相同的以分区数量为模的散列码,但仍在其中散列以实现高效查找。当使用组合记录的系统执行shuffle操作如groupBy时,他们可以将每个传出记录hash到目标复合记录的键。
  分区的最后一个有趣用例是复合数据结构,其中,数据结构的某些字段随时间更新,而其他字段不是。例如在PageRank中,有两种类型的数据,页面的link列表,不可变的、页面的rank,可变的。我们将其表示成两种RDD,(ID, links)键值对和(ID, ranks)键值对,他们由ID共同划分分区。系统优先将每个ID的排名和链接放在同一台机器上,但是我们可以单独更新排名而不更改链接。同样的技术被用于保持GraphX中顶点和边的状态。
  通常情况下,人们可以将RDD视为集群环境下更具声明性的内存抽象。在单台机器上使用内存时,程序员担心数据布局主要是为了优化查找和最大化共同访问的信息的colocation(托管)。在分布式内存上,RDD在出于相同的考虑下给予控制,通过让用户选择分区函数和共同分区数据集,但也避免要求用户准确指定每个分区的位置。因此,在运行时可以基于可用资源有效放置分区,或者在失败时移动他们,而程序员仍然控制访问性能。

3.2.3 处理不可变性

  RDD模型和专业系统的第三个区别是RDD是不可变的,不可变性对于谱系和故障恢复的推理很重要,尽管从根本上讲这和用于这一目的的可变数据集和跟踪版本号没什么区别。
不可变性和容错将会带来一些开销,在很多情况下,以下两种技术能够得到比较好的性能:

  1. 复合数据结构表示为多个共同分区的RDD,如PageRank例子中的数据集,允许程序仅仅修改需要改变的那部分数据的状态。在很多算法中,在绝大部分的迭代中,都有记录的某些域需要改变而其他不需要的情况。这一方法可以有效地抓住核心。
  2. 即使在记录中,当内部数据结构不变时,指针也可被用于从记录的先前版本中重用状态。举个例子,java中的string是不可变的。在一个(Int,String)的记录中使用map,改变了Int,但是保持了相同的String,将有个指针指向之前的String对象,而不是拷贝它。更一般地,来自函数式编程的持久化数据结构能够被用于将其它形式的数据(eg:哈希表)的增量更新表示为来自先前版本的增量。函数式编程的很多思想都能够直接帮助RDD。

3.2.4 实现自定义转换

  我们发现在某些应用中有用的最后一种技术是使用低级的RDD接口实现自定义依赖模式和转换。接口很简单,仅仅需要父RDD上的依赖列表和给定父RDD迭代器的情况下计算迭代器的分区的函数。我们在第一版的Shark和GraphX中实现的一些自定义的操作符的经验引发很多新的操作符被添加到Spark中。例如,mapPartitions,给定一个RDD[T]和一个从Iterator[T] 到 Iterator[U]的函数,通过应用到每个分区,返回RDD[U]。这非常接近RDD的最低级别接口,允许转换在每个分区内执行非功能性操作(eg:使用可变状态)。Shark同样包含用于替代内置操作符的自定义的join和groupBy。即使应用实现自定义转换,也将自动受益于RDD模型的容错、多租户、组合优势。同时也比单独的系统更容易开发。

3.3 Shark : SQL on RDD

  作为在RDD上实现了复杂的存储和处理的示例,Shark在经过深入研究的并行数据库领域取得了很好的性能,同时提供传统数据库缺少的容错和复杂分析能力。

3.3.1 动机

现代数据分析的几个挑战:

  1. 数据量正在迅速扩大,需求扩大到上百台商业机器的集群。
  2. 这种扩展也扩大了错误和落后者(慢任务)的发生率,使得并行数据库设计复杂化。
  3. 数据分析的复杂性也已经提高:现代数据分析采用复杂的统计方法,如机器学习算法,远远超出传统企业数据仓库系统的roll-up和drill-down能力。
  4. 尽管在规模和复杂性上都进一步提升,用户还是希望能够以可交互的速度查询数据。
      为解决“大数据”问题,探讨了两大系统:首先是由MapReduce和通用处理程序组成,提供适合于集群的细粒度的容错模型,在任务失败或者节点缓慢的情况下能够确定性地在其它节点重新执行。MapReduce也很通用:它可以表达很多统计和学习算法。它也很容易地支持非结构化数据和“schema-on-read”。然而,MapReduce缺乏很多使数据库高效的特性,因此导致了数
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值