文章目录
背景
RDDs(Resilient Distributed Datasets):弹性分布式数据集,一种分布式的内存抽象,允许程序员在大型集群中进行计算的容错方式。
发展背景:因为传统的并行计算(MapReduce)采用的是非循环式的数据流模型,使得在迭代计算和交互式计算要进行大量的 I/O 操作,而 RDDs 正是解决这一点的抽象方法。
分布式集群概念图:
MapReduce 流程图:以 WordCount 为例
主要有两个操作:
Map:将数据进行一系列操作转换得到结果的过程,在从节点执行Reduce:将数据整合成最终结果,在主节点执行
流程:input -> splitting -> mapping -> shuffling -> reducing -> result
产生的原因:
MapReduce和Drayd虽然已经被广泛应用到大规模的数据分析,但是缺乏对分布式内存的运用,使得需要重用中间结果的计算十分低效
低效的计算类型:
- 如迭代式机器学习和图算法:PageRank、K-means聚类和逻辑回归。
- 如
Ad-hoc查询:用户根据自己的需求,灵活的选择查询条件,系统能够根据用户的选择生成相应的统计报表
对传统 MapReduce 的改进:
- 迭代式图计算系统
Pregel Hadoop提供了一种迭代式MapReduce接口
仍然存在的问题:
- 仅支持特定的计算模式(循环一系列的
MapReduce操作),没有提供更加通用的数据重用的抽象能够让用户直接在内存中装载数据
已有解决方法的缺点:
- 基于集群的内存存储抽象:分布式共享内存,键值对存储,数据库等提供了基于细粒度更新可变状态的接口,运用这些接口时,达到数据容错的唯一方式是在不同的机器之间进行数据的冗余或者记录更新日志
- 细粒度:针对数据集中的某个元素进行转换操作
- 粗粒度:针对整个数据集进行转换操作,而不是针对数据集中的某个元素进行转换操作
- 对于数据密集型任务来说代价高昂,因为他们需要在集群网络间复制大量数据,同时带来大量的存储开销
- 数据密集型:大量的,复杂的、丰富多样的,快速变化的数据
本文的解决方法:
- 提出了一种能够广泛运用于各种应用中高效的数据重用抽象,弹性分布式数据集(
RDDs)。RDDs是一个容错的、并行的数据结构,能够让用户明确地在内存中持久化中间结果,控制其分区以优化数据的放置和使用丰富的操作符对其进行处理
Rdds 的特点:
- 读操作:粗粒度或细粒度
- 写操作:粗粒度
- 记录产生数据集的一系列转换操作(称为
lineage),而不记录真实的数据 - 当
lineage过长时,会设置检查点(checkpoint) - 如果
Rdd丢失了,有足够的信息知道自己是如何从其他Rdd产生的,从而重新计算该分区,因此丢失的数据可以很快的回复,而不需要昂贵的代价
弹性分布式数据集(RDDs)
- 弹性:横向有多个分区,纵向当计算过程中内存不足时可以写到外存上,当需要使用时交换到内存中
- 分布式:分布在多台机器进行并行计算
- 数据集:只读的抽象的数据集合
可以看做 lineage 图追踪不同版本化数据
简略 rdd 理解图
RDD有多个分区,每个分区指向数据或其他的RDD- 计算节点存储
RDD的一个或多个分区 - 分区就是依照特定规则,将具有相同属性的数据记录放在一起
如何产生 RDD
- 从稳定的物理存储中的数据集创建
- 由其他
RDDs通过转换操作产生
用户可以对 RDD 的控制
- 持久化:选择需要重用的
RDD的存储策略,设定特定的RDD只存在硬盘上,或是设置优先级,当内存不够时,将内存中的哪个数据放到硬盘中 - 分区: 可以选择
RDDs的分区方式,可以通过用户自定义的规则进行分区
Spark 提供的编程接口
- 转换(
transformations):map,filter- 所有的转换操作都是懒惰的
- 转换操作会产生新的
RDDs,每个RDDs又包含多个分区,一系列的转换操作就构成了相互依赖的多个RDDs组成的有向无环图(DAG)
- 动作(
actions):count,collect,save- 动作立即执行,返回结果
lineage 图示
- 假设某一个分区数据丢失,则在相应的分区上重新进行转换重建丢失分区
RDDs 表示
- 基于图表示
RDD之间的关系(lineage) - 一个公共接口表示每个
RDD的信息partitions():返回一组分区,是数据集的原子块preferredLocations(p):返回分区p存放的位置dependencies():返回该RDD的依赖(父亲)iterator(p,parentlters):基于父亲计算数据集partitioner():分区器,定义分区规则
依赖关系:
- 窄依赖(
narrow dependencies):父RDD的每个分区最多由子RDD的一个分区使用 - 宽依赖(
wide dependencies):一个子RDD依赖多个父RDD
这样区分的原因:
- 窄依赖关系可以在一个集群节点上顺序执行,节点故障时只需要重新计算父
RDD的分区 - 宽依赖关系需要所有父分区的数据计算完成后,再进行洗牌(
shuffle),因此单个节点故障可能导致所有的子孙丢失数据,从而需要完全重新执行计算
实现
使用了 14000 的 scala 代码实现了 spark
- 系统运行在
Mesos集群管理器上 - 可以与
hadoop、MPI和其他应用程序共享资源 - 每个
spark程序作为单独的Mesos应用程序运行,具有自己的驱动程序master和工作程序workers,应用程序之间的资源共享由Mesos管理 - 可以不用修改任何代码从
hadoop(hdfs 或 hbase) 读取数据
作业调度
调度思想
- 调度程序会基于数据的位置使用使用延迟调度将任务分配给机器,实现任务所需的数据就在其运行的节点上
延迟调度:将任务发布到其所需数据的机器上,若机器已经被占用则进行延迟等待,直到可以运行该任务或者超过了等待时间则将任务运行到其他机器上
阶段(stage)
- 当用户执行
action操作时,调度程序会检查该RDD的lineage图构建要执行阶段的DAG - 每个阶段尽可能包含多的窄依赖关系转换,阶段的边界是宽依赖所需的洗牌操作或已经计算过得分区。
- 对于宽依赖关系,会在父
RDD上记录中间结果以简化故障恢复 - 如果一个任务失败,一个阶段的父项仍然可用,则会在另一个节点重新运行;若某些阶段产生了数据丢失,则要重新提交任务计算丢失的分区
解释器整合
scala 解释器
scala提供了Ruby和Python的交互式shellScala解释器为用户键入的每一行编译一个类,该类包含一个单例对象,该对象包含该行上的变量或函数,并在初始化方法中运行代码
例子:
Line1: var x = 5
Line2: println(x)
- 解释器会编译一个包含
x的Line1类 - 第二行编译为
println(line1.getInstance().x)
spark 解释器
做了两点改动:
- 类传输:支持基于
HTTP传输类字节码文件,这样worker节点就能获取输入的每行代码对应的字节码 worker直接引用各个行对象的实例
内存管理
- 序列化:将变量从内存中变成可存储或传输的过程
- 反序列化:把变量内容从序列化的对象重新读到内存里
Spark 提供了三种持久化的 RDD 选项:
- 反序列化
Java对象的内存存储 - 序列化数据的内存存储
- 硬盘存储
内存替换:
- 当新的
RDD分区没有足够的内存存储时触发 - 使用
LRU(Least Recent Used最近最少使用)策略替换 - 用户可以设定
RDD持久化优先级提供进一步控制
检查点的支持
- 尽管在故障的时候可以通过
lineage来恢复RDD。但是对于具有非常长的lineage的RDD来说,则恢复是十分耗时的,因此将一些RDD检查点存放到稳定存储中会减少恢复的耗时 - 检查点技术主要对具有宽依赖关系的
RDD比较有用,对于窄依赖关系的RDD用处不大
评估
迭代式机器学习应用
实现了两个迭代机器学习应用程序,逻辑回归和 k-means,以比较以下系统的性能:
Hadoop:0.20.2稳定的发行版本HadoopBinMem:在首轮迭代中执行预处理,通过将输入数据转换成为开销较低的二进制格式来减少后续迭代过程中文本解析的开销,在HDFS中加载到内存。Spark:基于RDDs的实现。
- 由于
HadoopBinMem首先要执行数据转换为二进制的任务,所以在首次迭代中速度最慢 - 而在后续的迭代中,由于
HadoopBinMem解析文本的开销较小,因此速度优于Hadoop - 而
Spark均是速度最快的
- 对于逻辑回归,
Spark在100台机器上分别比Hadoop和HadoopBinMem快25.3倍和20.7倍 - 对于计算密集型的
k-means应用程序来说,Spark仍然实现了1.9倍到3.2倍的加速
理解速度提升
会发现 Spark 甚至比内存存储二进制数据的 Hadoop(HadoopBinMem)还要快 20 倍。在 HadoopBinMem 中,我们使用了 Hadoop 的标准二进制格式(SequenceFile)和 256MB 大小的超大块,并且我们强制 HDFS 的数据目录位于内存文件系统中
由于以下因素,Hadoop 仍然运行缓慢:
Hadoop软件堆栈的最小开销,运行一个Hadoop空作业,仅仅执行作业的初始化、启动任务、清理工作就至少耗时25秒- 提供数据时
HDFS的开销,每一个HDFS数据块,HDFS进行了多次复制以及计算校验和操作(一致性问题) - 将二进制记录转换为内存中的
Java对象的反序列化成本
PageRank
网页排名,是 Google 公司所使用的对其搜索引擎搜索结果中的网页进行排名的一种算法
Spark在30个节点上的速度比Hadoop提高了2.4倍,控制RDD的分区以使其在迭代中保持一致,将提高到7.4倍- 加速也能几乎线性地扩展到
60个节点上
数据集在内存中不同百分比的表现
- 随着数据集在内存中的比重增加,迭代时间随之减小
交互式数据挖掘
为了演示 Spark 交互式查询大数据集的能力,我们用它来分析 1TB 的维基百科页面浏览日志(2年的数据),在输入的数据集上获取所查询页面的浏览总数:
- 全部页面
- 页面的标题能精确匹配给定的关键词
- 页面的标题能部分匹配给定的关键词
- 实验分别在整个, 1 2 \frac{1}{2} 21, 1 10 \frac{1}{10} 101 的数据集上查询的响应时间,结果表示比直接在磁盘上操作快了几个数量级
- 实验结果表明
RDD缓存会使得Spark成为一个交互式数据挖掘的强度工具
总结
RDDs是一种高效、通用、容错的用于集群应用程序中共享数据的抽象,不记录真实数据,而是记录数据转换的关系和数据存放的位置RDDs提供粗粒度转换的操作,使得能够用lineage有效的恢复数据- 对于窄依赖关系直接计算父
RDD的相对应的分区,宽依赖关系通过在父RDD记录中间结果简化故障恢复,对于长的lineage则设置检查点简化恢复操作 RDDs支持用户对数据进行持久化和分区操作- 调度主要思想是移动计算而不是移动数据
- 内存不足时可以暂时存放到外存中,有需要再换进内存
本文介绍弹性分布式数据集(RDD),它是解决传统并行计算在迭代和交互式计算中大量I/O问题的抽象方法。阐述了RDD的产生、特点、用户控制及Spark编程接口,还介绍了其实现、作业调度等内容。评估显示,RDD在迭代式机器学习、PageRank等应用中表现出色,能显著提升效率。

2836

被折叠的 条评论
为什么被折叠?



