[Berkeley]弹性分布式数据集RDD的介绍(RDD: A Fault-Tolerant Abstraction for In-Memory Cluster Computing 论文翻译)
摘要:
虽然如此,RDD仍然足以用于非常多类型的计算。包含专用的迭代编程模型(如Pregel)等。我们已经将RDD应用到Spark系统之中,并对改性进行了相关的评估。
假设不能非常好地使用内存。那么,当一些应用的数据结果须要多次复用的情况出现的时候,运行效率就会受到影响。这些应用一般包含:
此外。我们还在Spark之上实现了Pregel和HaLoop编程模型(包含其位置优化策略),以库的形式实现(分别使用了100和200行Scala代码)。
- RDD Abstraction抽像
RDD始终不须要物化。RDD含有怎样从其它RDD衍生(即计算)出本RDD的相关信息(即Lineage信息)。据此能够从物理存储的数据计算出对应的RDD分区。
用户能够请求将RDD缓存,这样执行时将已经计算好的RDD分区存储起来,以加速后期的重用。相关策略:缓存的RDD默认存储在内存中,但假设内存不够,能够写到磁盘上;用户也能够使用其它的存储策略。比方只将RDD存储在磁盘等等;用户还能够在每一个RDD上面指定优先级来确定最先spill到磁盘的RDD。
这有助于部署的优化。比如,我们能够将两个数据集用相同的方式进行 hash-partitioned以便于之后的join操作(事先经过key进行了划分)。
- Spark Programming Interface
动作是向应用程序返回值。或向存储系统导出数据的那些操作,比如,count(返回RDD中的元素个数)。collect(返回元素本身),save(将RDD输出到存储系统)。
在Spark中,仅仅有在RDD上第一次运行actions 操作时,才会真正開始计算RDD(即延迟计算)。
假定有一个大型站点出错,操作员想要检查Hadoop文件系统(HDFS)中的日志文件(TB级大小)来找出原因。通过使用Spark。操作员仅仅需将日志中的错误信息装载到一组节点的内存中,然后运行交互式查询就可以。
<strong>lines </strong>= spark.textFile("hdfs://...") errors = lines.filter(_.startsWith("ERROR"))
errors.cache()
<span style="font-size:18px;"> // Count errors mentioning MySQL
errors.filter(_.contains("MySQL")).count()
// Return the time fields of errors mentioning
// HDFS as an array (assuming time is field
// number 3 in a tab-separated format):
errors.filter(_.contains("HDFS"))
.map(_.split('\t')(3))
.collect()</span>
lines由于错误信息可能仅仅占原数据集的非常小一部分(小到足以放入内存)。
Spark调度器以流水线的方式运行后两个转换,向拥有errors分区缓存的节点发送一组任务。此外。假设某个errors分区丢失,Spark仅仅在对应的lines分区上运行filter操作(“血统”信息记录操作过程)来重建该errors分区。
- Advantages of the RDD Model(分布式共享内存)
并且。失效时仅仅须要又一次计算丢失的那些RDD分区。能够在不同节点上并行运行,而不须要回滚整个程序。
第一,对于RDD中的批量操作,执行时将依据数据存放的位置来调度任务,从而提高性能。第二。对于基于扫描的操作。假设内存不足以缓存整个RDD。就进行部分缓存。
把内存放不下的分区存储到磁盘上。此时性能与现有的数据并行系统差点儿相同。
RDD上的非常多动作(如count和collect)都是批量读操作,即扫描整个数据集,能够将任务分配到距离数据近期的节点上。同一时候。RDD也支持细粒度操作,即在哈希或范围分区的RDD上运行keyword查找。
- Applications Not Suitable for RDDs
RDD不太适合那些异步更新共享状态的应用。比如并行web爬行器。因此,我们的目标是为大多数批量分析型应用提供有效的编程模型。此外类型的应用交给专门的系统来处理。
我们选择Scala是由于它简洁(特别适合交互式使用)、有效(由于是静态类型)。
可是,RDD抽象并不局限于函数式语言。
Worker是长时间执行的进程。将RDD分区以Java对象的形式缓存在内存中。
Scala将闭包表示为Java对象。这些对象在传递的时候被序列化,通过网络传输到其它节点上进行装载。Scala将闭包内的变量保存为Java对象的字段。比如。var
x = 5; rdd.map(_ + x) 这段代码将RDD中的每一个元素加5。
只是。我们举的样例差点儿都省略了这个类型參数。由于Scala支持类型判断。
无论如何,我们都不须要改动Scala编译器。
- RDD Operations in Spark
- Example Applications
假设这些算法的工作集可以放入内存,将极大地加速程序执行。
算法採用梯度下降的方法:開始时w为随机值,在每一次迭代的过程中,对w的函数求和。然后朝着优化的方向移动w。
<span style="font-size:18px;">val points = spark.textFile(...)
.map(parsePoint).persist()
var w = // random initial vector
for (i <- 1 to ITERATIONS) {
val gradient = points.map{ p =>
p.x * (1/(1+exp(-p.y*(w dot p.x)))-1)*p.y
}.reduce((a,b) => a+b)
w -= gradient
}</span>
之后的小节我们将看到这样的在内存中缓存points的方式,比每次迭代都从磁盘文件装载数据并进行解析要快20X。
- PageRank
<span style="font-size:18px;">// Load graph as an RDD of (URL, outlinks) pairs
val links = spark.textFile(...).map(...).persist()
var ranks = // RDD of (URL, rank) pairs
for (i <- 1 to ITERATIONS) {
// Build an RDD of (targetURL, float) pairs
// with the contributions sent by each page
val contribs = links.join(ranks).flatMap {
(url, (links, rank)) =>
links.map(dest => (dest, rank/links.size))
}
// Sum contributions by URL and get new ranks
ranks = contribs.reduceByKey((x,y) => x+y)
.mapValues(sum => a/N + (1-a)*sum)
}</span>
<span style="font-size:18px;"> links = spark.textFile(...).map(...)
.partitionBy(myPartFunc).persist()</span>
理想的话,一个运行RDDs相关操作的系统应该尽可能多的提供转换算子,而且同意用户随意组合这些算子。关于上述的挑战,一个简单的基于图的RDDs表示法有助于目标的完毕。
在Spark中已经開始使用。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
dependencies):子RDD的多个分区能够依赖一个父RDD分区。比如。map产生窄依赖,而join则是宽依赖(除非父RDD被哈希分区)。还有一个样例见下图:
首先,窄依赖同意在一个集群节点上以流水线的方式(pipeline)计算全部父分区。比如。逐个元素地运行map、然后filter操作;而宽依赖则须要获取全部父分区数据,然后在节点之间进行Shuffle,这与MapReduce类似。第二,窄依赖可以更有效地进行失效节点的恢复,即仅仅需又一次计算丢失RDD分区的父分区,并且不同节点之间可以并行计算。而对于一个宽依赖关系的Lineage图,单个节点失效可能导致这个RDD的祖先产生冗余计算开销。
第二。数据丢失时,对于窄依赖仅仅须要又一次计算丢失的那一块数据来恢复;对于宽依赖则要将祖先RDD中的全部数据块全部又一次计算来恢复(在宽依赖情况下,丢失一个子RDD分区须要又一次计算的每一个父RDD的每一个分区的全部数据并非都给丢失的子RDD分区用的(groupbykey()),会有一部分数据相当于相应的是未丢失的子RDD分区中须要的数据。这样就会产生冗余计算开销,这也是宽依赖开销更大的原因)。所以在长“血统”链特别是有宽依赖的时候,须要在适当的时机设置数据检查点(Tachyon中已经通过Edge算法实现,见Tachyon论文翻译)。
也是这两个特性要求对于不同依赖关系要採取不同的任务调度机制和容错恢复机制。
以下给出一些RDD的实现实例:
map:不论什么RDD上都能够运行map操作,返回一个MappedRDD对象,该对象与父RDD具有同样的分区以及偏好位置。该操作传递一个函数參数给map,对其父RDD上的记录依照iterator的方式运行这个函数。
通过对应父RDD上的窄依赖关系计算每一个子RDD分区(注意union操作不会过滤反复值,相当于SQL中的UNION ALL)。
cogroup之后形成的新RDD。对每一个key下的元素进行笛卡尔积操作)。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
系统执行在Mesos集群管理之上,且能够与Hadoop、MPI以及其它应用进行资源共享(兼容)。每个Spark程序作为一个独立的Mesos应用执行,且都有自己的driver(master)和workers。应用之间的资源共享由Mesos来处理。
- Job Scheduling
本例不用再执行stage 1,由于B已经存在于缓存中了,所以仅仅须要执行2和3。
假设某些stage不可用(比如。Shuffle时某个map输出丢失),则须要又一次提交这个stage中的全部任务来并行计算丢失的分区。
- Interpreter Integration(解释器的集成)
基于内存的数据能够实现低延迟,我们希望同意用户从解释器交互式地执行Spark,从而在大数据集上实现大规模并行数据挖掘。
这个类是一个包括输入行上的变量或函数的单例对象,且会用一个初始化函数执行这行代码。
比如,假设用户输入代码var x =
5,接着又输入println(x),则解释器会定义一个包括x的Line1类。并将第2行编译为println(Line1.getInstance().x)。
所以worker节点不会收到x。所以,我们将这样的代码生成逻辑改为直接引用各个行对象的实例。
下图说明了解释器怎样将用户输入的一组代码行解释为Java对象。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
我们计划以Spark解释器交互式地执行高级数据分析语言。比方类似SQL。
- Memory Management
我们发现这个默认的策略至今为止在我们的应用中都工作的非常好。我们也为用户提供了更深一步的控制策略:为每个RDD提供持久化存储。
- Support for Checkpointing
总的说来。结果例如以下:
这样的加速比是由于:Spark中数据以Java对象的形式存储在内存中。进而避免了过多的I/O操作以及反序列化操作。
(2)用户编写的应用程序运行结果非常好。特别地,Spark分析报表比Hadoop快40多倍。
(3)假设节点发生失效。通过重建那些丢失的RDD分区,Spark可以实现高速恢复。
(4)Spark可以在5-7s延时范围内,交互式地查询1TB大小的数据集。
- Iterative Machine Learning Applications
K-means的迭代时间取决于更新聚类坐标(计算过程)耗时,Logistic回归是非计算密集型的。可是在I/O操作和解析过程中很耗时。
因为典型的机器学习算法须要数10轮迭代才干够收敛,我们分别统计了首轮迭代和兴许迭代计算的耗时,并从中发现,通过RDD进行数据共享极大地加快了兴许迭代的速度。
图7显示了兴许迭代的平均耗时,图8对照了不同大小集群条件下耗时情况。从图8(a)我们发现,在100个节点上执行Logistic回归程序。Spark比Hadoop、HadoopBinMem分别快25.3、20.7倍。
从图8(b)能够看到,虽然是更加典型的计算密集型的K-means应用,Spark仍旧比Hadoop、HadoopBinMem分别快1.9、3.2倍,这是由于K-means程序的计算开销是基本的(用很多其它的节点有助于提高计算速度的倍数)。
可是,使用预先转换的SequenceFile文件(Hadoop内建的二进制文件格式)的 HadoopBinMem,在兴许迭代中节省了解析的代价。可是仍然会带来其它的开销,如从HDFS读SequenceFile文件并转换成Java对象等。由于Spark是直接读取缓存于RDD中的Java对象的。随着集群尺寸的线性增长,迭代时间大幅下降。性能得到提升。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
对于2。我们发现为了服务每个HDFS数据块,HDFS进行了多次内存复制以及计算校验和操作。必定会带来对应的开销。
- PageRank
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
- Fault Recovery
没有不论什么失败的情况下。每轮迭代启动了400个任务处理100G数据。
Spark调度器调度这些任务在其它节点上又一次并行执行:又一次读取一直的输入数据并基于Lineage信息重建RDD。这使得迭代计算耗时添加到80秒。一旦丢失的RDD分区被重建,平均迭代时间又回落到58秒。
并且,系统须要通过网络将应用中多达100GB的数据进行复制。由于复制,Spark也许须要花费两倍的内存来完毕备份工作。
相反。我们样例中的RDD的“血统”图的存储只须要10KB大小的空间(存储在磁盘)。
- Behavior with Insufficient Memory(内存不足)
- User Applications Built with Spark
DISTINCT等)须要使用单独的MapReduce作业。
在Hadoop集群上处理200G压缩数据生成的报告耗时20小时。而使用Spark基于96G内存的2个节点只需耗时30分钟就可以完毕,主要是由于Spark只将符合用户要求的信息的行列数据存储到了一个RDD里面,而不须要存储整个解压缩的文件。
使用一个交通模型。可以预计跨多个公路网行驶的耗时,由此,系统可以估算交通的拥堵状况。
研究人员使用Spark实现了一个可迭代的EM(最大期望)算法,算法迭代地反复运行map、reduceByKey操作。
应用从20个节点扩展到80个节点(每一个节点4核),如图13(a)所看到的。
图13(b)显示了基于50G数据子集的分类器的训练结果,整个数据集包含250000的URL、至少10^7个与网络相关的特征/维度以及每一个URL相应页面的内容属性。随着节点的添加,这并不像交通应用程序那样近似线性,主要是由于每轮迭代的固定通信代价较高。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
- Interactive Data Mining(交互式数据挖掘)
图14 显示了分别在整个、1/2、1/10的数据集上查询的响应时间,甚至1TB数据在Spark上查询仅耗时5-7秒,这比直接操作磁盘数据快几个数量级,比如,从磁盘上查询1TB数据耗时170秒。这表明了RDD缓存使得Spark成为一个交互式数据挖掘的强大工具。
- Expressing Existing Programming Models
Parallel。总体同步并行计算模型)中。程序由一系列超步(Superstep)协调迭代执行在每一个超步中,各个顶点执行用户函数,并更新对应的顶点状态。改变图的拓扑结构。然后向下一个超步的顶点集发送消息。
这样的模型可以描写叙述非常多图算法,包含最短路径,双边匹配和PageRank等。
另一点非常重要,RDDs能够同意我们像Pregel一样将定点状态信息存储在内存中,这样就能够通过控制RDD的分区来优化集群节点之间的交互了。也能够支持部分的错误回复。
这些系统运行和Dryad类似的总体操作。可是会在分布式文件系统中存储状态。将中间状态放入RDDs中能够加速处理过程。
特别地,尽管RDDs只只能通过总体的转换操作来创建,可是非常多的并行程序自然地会对记录採用同样的操作(适合总体操作的模式)。
相似地,RDDs的不可变性也不是什么障碍。由于我们能够创建多个RDD来来代表同样数据集的不同版本号。
其实,眼下使用文件系统的非常多的MapReduce应用都不支持文件的更新操作。
- Leveraging RDDs for Debugging
特别地,通过记录一个job期间创建的“血统”信息,我们之后能够又一次计算这些RDDs,也能够让用户交互式地查询这些信息。进而能够在一个单进程的debugger过程中通过又一次计算相应的RDD分区来又一次执行来自一个job的不论什么的task(有针对性地获取“血统”信息。并有针对性地对单个partition进行计算来针对性地重执行单个task)。不像传统分布式系统那样通过又一次执行app来进行bug调试的调试者。必须在较多的nodes间搞清楚事件的执行顺序。相对而言,RDDs的debug过程没有添加不论什么负载,由于仅仅有RDD的“血统”图须要被记录,我们眼下也正基于上述的观点开发一个Spark调试器。
- Cluster Programming Models
然而,在这些系统中,并行的数据获取对象能够是磁盘中的文件或者是用于查询过程的临时的数据集。且系统会通过同样的算子来进行流水线式的数据处理(比方一系列的map操作),可是同样的算子的处理过程中,数据共享的效率太低。
然而,这些系统会为他们支持的计算模块提供数据共享。不会为用户提供普遍的数据共享的抽象。比如。用户无法使用Pregel或者Twister来将一个数据集载入到内存。并决定哪个数据查询的操作能够在上面运行。
DSM(Distributed
shared memory )以及key-value存储(比方RAMCloud提供了相似的模型)也是类似的。
可是Nectar并没有提供In-Memory缓存(使用一般的分布式文件系统)。也不可以让用户显式地控制应该缓存那个数据集,以及怎样对其进行分区。Ciel和FlumeJava相同可以记住任务结果,但不能提供In-Memory缓存并显式控制它的缓存方式。
然而在这些系统中,“血统”信息会在一个job结束之后丢失,最后还是须要採用在存储系统进行复制备份的方法来共享计算的数据。相反,RDDs用"血统"机制高效地将数据缓存至内存而不须要复制和I/O的开销。
不像已经存在的通过数据复制进行容错处理的集群存储抽象。RDD基于粗粒度的转换操作提供了一些列的API,这些API可以基于“血统”机制进行高效率的数据恢复。
使用RDD的Spark系统实现处理迭代式作业的速度超过Hadoop大约20倍,并且还可以交互式查询数百GB的数据。
[Berkeley]弹性分布式数据集RDD的介绍(RDD: A Fault-Tolerant Abstraction for In-Memory Cluster Computing 论文翻译)的更多相关文章
- RDD(弹性分布式数据集)及常用算子
RDD(弹性分布式数据集)及常用算子 RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是 Spark 中最基本的数据 处理模型.代码中是一个抽象类,它代表一个 ...
- Spark的核心RDD(Resilient Distributed Datasets弹性分布式数据集)
Spark的核心RDD (Resilient Distributed Datasets弹性分布式数据集) 原文链接:http://www.cnblogs.com/yjd_hycf_space/p/7 ...
- RDD内存迭代原理(Resilient Distributed Datasets)---弹性分布式数据集
Spark的核心RDD Resilient Distributed Datasets(弹性分布式数据集) Spark运行原理与RDD理论 Spark与MapReduce对比,MapReduce的计 ...
- Spark - RDD(弹性分布式数据集)
org.apache.spark.rddRDDabstract class RDD[T] extends Serializable with Logging A Resilient Distribut ...
- Spark核心类:弹性分布式数据集RDD及其转换和操作pyspark.RDD
http://blog.csdn.net/pipisorry/article/details/53257188 弹性分布式数据集RDD(Resilient Distributed Dataset) 术 ...
- RDD弹性分布式数据集的基本操作
RDD的中文解释是弹性分布式数据集.构造的数据集的时候用的是List(链表)或者Array数组类型/* 使用makeRDD创建RDD */ /* List */ val rdd01 = sc.make ...
- Spark弹性分布式数据集RDD
RDD(Resilient Distributed Dataset)是Spark的最基本抽象,是对分布式内存的抽象使用,实现了以操作本地集合的方式来操作分布式数据集的抽象实现.RDD是Spark最核心 ...
- 【Spark】Spark核心之弹性分布式数据集RDD
1. RDD概述 1.1 什么是RDD (1) RDD(Resilient Distributed Dataset)弹性分布式数据集,它是Spark的基本数据抽象,它代表一个不可变.可分区.里面的元素 ...
- 弹性分布式数据集RDD概述
[Spark]弹性分布式数据集RDD概述 弹性分布数据集RDD RDD(Resilient Distributed Dataset)是Spark的最基本抽象,是对分布式内存的抽象使用,实现了以操作 ...
随机推荐
- C# 客户端读取共享目录文件
控制台应用程序 using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...
- Windows下压缩成tar.gz格式
tar.gz 是linux和unix下面比较常用的格式,几个命令就可以把文件压缩打包成tar.gz格式,然而这种格式在windows并不多见,WinRAR.WinZip等主流压缩工具可以释放解开,却不 ...
- http链接中请求进行编码,Http请求
如果参数中含有特殊字符&,则强制URL编码<br> http协议中参数的传输是"key=value"这种简直对形式的,如果要传多个参数就需要用“&”符号 ...
- jdbc分页查询
虽然现在db层的框架很多,用起来也非常的方便,像分页这种非常常用的功能也基本上都有对应的接口可以直接使用.但是有时候数据源不在配置的范围的时候,就必须要使用到jdbc来执行sql,jdbc执行的是原生 ...
- ubuntu16.04安装teamviewer12
安装teamviewer下载地址:http://www.teamviewer.com/en/download/linux/ 下载的是:teamviewer_12.0.76279_i386.deb ...
- (转)全文检索技术学习(一)——Lucene的介绍
http://blog.csdn.net/yerenyuan_pku/article/details/72582979 本文我将为大家讲解全文检索技术——Lucene,现在这个技术用到的比较多,我觉得 ...
- 创建一个 Vue 的实例
每个 Vue 应用都是通过 Vue 函数创建一个新的 Vue 实例开始的: var vm = new Vue({ // 选项 }) 选项:el.data.methods el: 类型: ...
- 新安装数据库sqlserver2008r2,使用javaweb连接不上问题处理
鼠标右键[计算机]-->[管理],打开界面如下: 选择自己数据库的实例名: 选择TCP/IP:右键[属性],将所有TCP动态端口的[0]删掉,TCP端口设为1433:重启服务,即可连接. PS: ...
- docker 1-->docker swarm 转载
实践中会发现,生产环境中使用单个 Docker 节点是远远不够的,搭建 Docker 集群势在必行.然而,面对 Kubernetes, Mesos 以及 Swarm 等众多容器集群系统,我们该如何选择 ...
- 关于Extjs的窗口拖拽,改变大小,背景淡化问题
大部分Extjs的Windows问题:在Extjs4代码中,只要加几句话: frame:true, //这个窗口的边边是圆的 border : false , //窗口没有边框 draggable: ...