Spark概述
本文转载自:柳浪闻莺的博客
其实做大数据的我早应该去好好了解一下spark了,但是个人的学习状况不是很好,一直没有去研究。这几天找时间了解了一下Spark,这里简单描述下Spark的一些知识。
1 Hadoop等大数据分析工具的问题以及未来趋势
有问题才有发展,如果Hadoop足够完美,那么就没有Spark什么事了。但是有两个因素决定不可能有完美的东西:一、只要稍微复杂点的东西就无法保证像1+1=2那样完美无瑕;二、任何事物无法逃脱时代的局限性,也就是时代发展了,这些东西就过期了。
那么现在的hadoop有什么问题呢?
- 最大的也是吐槽最多的一个问题自然是hadoop的MR只是一个框架,就像J2EE一样。如果你要使用,你必须有一个码农将你的业务逻辑实现成 Java(或者其他语言)代码。每当有业务升级,代码也得相应升级。易用性受到极大的限制,这也是Hive、Pig等产品的出发点。
- 另外MR的框架并不是完美的,有一些逻辑使用MapReduce无法非常好的实现,因为每个Map或者每个Reducer之间都是无关联的。只有 一个partition能够做一次数据的重组。举个最简单的例子:我们要按照一个公共key拼接两个数据,数据1中每条数据的key为A1,A2,A3, 而数据B中的每条数据的key为Ai。那么我们无法实现分桶,因为数据1无法确定要去哪个reduce,我们只能将数据1拷贝多份,扔到好几个 reducer中去。
- 还有一个是Hadoop大量使用了磁盘,磁盘的IO实在不敢恭维。比如我们的计算是一个串行的流,我们每个MR的中间结果还得扔到磁盘中去,其实这些中间结果并不需要持久化。
- 还有包括namenode的单点问题等问题
而Spark就是为了解决这些问题而生的。
2 Spark的特色
我们打开Spark的主页可以看到Spark的几个特点:
- Speed:内存计算速度是hadoop的100倍,磁盘计算则是10倍(Spark拥有更高级的DAG框架以及内存计算功能)
- Ease of Use:可以使用Scala、Java或者python快速开发(拥有超过80个的抽象操作集成在Spark API中)
- Generality:集合了Streaming、SQL以及高级数据处理等功能(其实就是在Spark之上可以使用Shark SQL、Shark Streaming、MLLib(machine learning lib)、GraphX等软件而已)
- Integrated with Hadoop:完美支持Hadoop(可以在Yarn上面跑Spark,可以使用HDFS数据进行Spark计算,其实这就是为了吸引Hadoop的用户)
我们简单看一下可以看到,其中2、3都是为了提高易用性,方便实现更多的业务,同时支持更快的开发。而1为了提高执行效率。至于4我们暂时不需要理 会,这是一个产品推广的特色。我们看到Spark在推广的时候刺中了Hadoop的许多痛点,让那些在使用Hadoop的人顿时感觉到:我靠,原来还有这 么好使的东西,那我还玩什么Hadoop,赶紧从了Spark吧!说句题外话,这也是做宣传的一个好方法,宣扬同类产品的不足之处,拿自己的优点和别人的 缺点比。你可以看到老罗做手机发布会的时候必然会这么搞。
3 Spark的关键特性RDD
这一节描述下Spark的关键特性:RDDs(Resilient Distributed Datasets)。RDD具有许多重要的特性,可以简单划分成:内存计算、故障容忍两部分。
3.1 RDD简介
RDDs是Spark的核心内容,大家可以通过研读这篇论文来 学习RDD的相关内容(PS:这篇论文有点老,也许现在的Spark又进步了)。RDD在Spark的官方文档中的解释为:RDD is a fault-tolerant collection of elements that can be operated on in parallel。我们关注几个关键词:fault-tolerant、in parallel。首先它是故障容忍的,其实它是并行计算的element(可以理解为数据)。事实上RDD提出了两个重要的思想:1.将数据cache 在内存中,大大减少磁盘的IO;2.方便而快速的恢复某些RDD失效的问题。当然,在易用性方面,RDD也是非常高端,提供了大量的API,但是本文就不 讨论了,因为技术上面意义不大。
3.2 RDD的作用和意义
通过上面贴的那篇论文,我们可以知道RDD可以解决两类常见的应用问题,一类叫做iterative(迭代)计算,比如machine learning、graph algorithm(机器学习和图形算法),另一类叫做interactive(交互)计算,比如对一份大数据进行大量的ad-hoc查询。第一类计算遇 到的问题是中间结果会被重复使用,如果使用MR框架,这些中间结果需要持久化到磁盘,每次使用得再读磁盘,太慢了!第二类计算遇到的问题是,这一份大数据 放在磁盘中,我每次查询都得读磁盘,太慢了!所以内存计算应运而生。RDD将这些需要重复使用的数据放置到内存中,使得数据的计算速度大大加快,这也就是 前面提到的比hadoop快XXX倍的一大原因。而我们可以看到,这个RDD的根本出发点就在于,有些数据我们往往会多次使用,放到内存必然能够加快访问 速度。
某些同学可能都已经看出来了,其实这就是cache的原理——将某些数据cache到高一级的存储介质中,以命中cache来减少对低级存储的访问频率。
3.3 内存计算
看了上面的解释,其实大家已经比较清楚内存计算这件事情了——不过就是把数据放到内存中而已。
更详细的,Spark中将计算分为两类:Action和Transformation。Action是指不产生新数据集的计算,比如count(统 计行数)、比如reduce(汇集数据,是的,它不产出新的数据,只是汇集而已)。而相应的Transformation则是产生新数据集的计算,比如 map、filter、union(拼接)。显然可以看到Transformation才是我们要关注的内容,因为涉及到中间数据的问题。那么 Transformation可以认为是从一个或多个RDD到另一个或者多个RDD的操作。那么这些操作可以用一个DAG图来完全描述,所有的节点都是一 个RDD,而有向边则是transformation。这样我们就可以将其中那些出度(Out-degree)较大的节点存到内存中,这样,这些使用此节 点的transformation都可以得到更高的执行速度。回到前面说的interactive计算,就是这个情况的最好样例,大量的ad-hoc查询 都会访问基础数据,所以将其放置在内存中是个great idea!
需要注意的是,Spark为我们提供了最大的自由度,所有的数据都可以由我们来进行cache的设置,包括是否要cache以及如何cache。cache有几种:
- MEMORY_ONLY:内存、非序列化方式,最快,但是如果超过内存限制,则会将某些数据丢弃,在需要的时候再计算(recomputed on the fly)
- MEMORY_AND_DISK:基本同上,唯一不同是,如果超过内存限制,存到磁盘
- MEMORY_ONLY_SER:和MEMORY_ONLY一致,但是会序列化
- MEMORY_AND_DISK_SER:和MEMORY_AND_DISK类似,但是会序列化
- DISK_ONLY:磁盘
最后cache还可以做副本,防止数据丢失重算。我们可以看到这个cache的方案相当完善,自由度相当大。
最后还有一个问题是内存中的数据expire,如果有大量的数据要进入内存,那么Spark会采用LRU(least recent used)算法清除某些RDD,据论文介绍,LRU还是非常好使的。
3.4 故障容忍
故障容忍是指如果数据的某个partition(块)缺失了,那么可以通过重新计算的方式,将这一块partition再次生成。这里RDD首先要解决一个依赖的问题
3.4.1 narrow dependency和wide dependency
依赖分为两种:narrow dependency和wide dependency。前者是指——单纯的一对一依赖,也就是我们熟知的map操作,我们通过一块数据产出了另一块数据,比如简单的filter就是。后 者是指——复杂的多对多依赖,聪明的同学可能已经知道了,就是类似reduce的依赖,比如group by key。Spark必须支持这两种依赖,因为他们都无可替代。
通过依赖的划分,我们可以将计算流变成更为简单的DAG图,而不是按照RDD来进行区分。论文中提出了stage这个概念:连续的narrow依赖可以合并成一个stage,因为他们可以在一个数据存放node本地执行。所以DAG图会变成如下所示:
3.4.2 故障恢复
当某个块丢失,Spark就会尝试恢复这一个块,那么会根据整个DAG图中的数据流来查阅数据,如果某个数据已经在内存中,就不需要再计算了,否则 需要执行一次计算。最终将数据计算出来。那么我们来看两种dependency对恢复的影响。我们可以看到narrow依赖可以更方便的恢复,因为一块数 据对应另一块数据。我们为了恢复某一个数据,只需要使用它对应的另一块源数据计算就可以了。但是wide依赖就麻烦多了,某一块数据的数据源来自众多的 块,我们只能将上游全部计算才能恢复数据。
4 总结
对Spark的接触还不是很多,只是看了一些文档,可以看到Spark确实解决了一些Hadoop无法解决的问题,内存计算的优势相当巨大。但是可 以看到两个阻碍:一是现在的Hadoop集群的内存是否能够支持Spark如此巨大的内存使用需求,如果内存较小,使用LRU策略是否会有问题。二是 Spark相当自由,需要用户设定数据的cache方案等配置,这会造成用户入门难度,以后是否会添加比较智能的自动cache,这也是一个问题。