核心内容:
1、RDD入门笔记1
今天又迈出了一步—涉猎RDD,好吧,进入文章的正题:RDD是一个容错的,并行的数据结构,可以控制将数据存储到磁盘或内存中,能够获取数据的分区。通常数据处理的模型包括:迭代计算、关系查询、MapReduce、流失处理等。Hadoop采用MapReduce模型,Storm采用流式处理模型,而Spark则实现了以上所有的数据处理模型。(呵呵,Spark就是厉害啊!)
首先我们先谈一谈数据集和工作集的工作方式:
数据集:基于数据集的处理工作方式就是从物理存储设备上加载数据,然后操作数据,然后写入物理存储设备,基于数据集的处理方式的代表就是Hadoop的MapReduce。
然而由于基于数据集的处理工作方式每次都要从物理存储设备上读取数据,然后操作数据,然后写回物理设备。导致基于数据集的处理方式有几种场景不试用:
1、不适合于大量的迭代算法。所谓迭代就是每一步对数据执行相似的函数(操作),Hadoop的MapReduce不适用这种场景。
2、不适合于交互式查询。
呵呵,交互式的含义—-计算机术语“交互式”:
系统与操作人员以人机对话的方式一问一答,直至获得最后处理结果。采用这种方式,程序设计人员可以边设计,边调整,边修改,使错误和不足之处及时得到改正和补充。特别对于非专业的操作人员,系统能提供提示信息,逐步引导操作者完成所需的操作,得出处理结果。这种方式和非交互式处理相比具有灵活、直观、便于控制等优点,因而被越来越多的信息处理系统所采用。
由于基于数据集的工作方式每次的查询都需要从磁盘上读取数据,然后执行查询,然后在写回数据结果,每一次都必须这样,这样效率等等都是一个问题。
3、基于数据流的方式不能够复用曾经的结果或中间计算结果,这点是最致命的。
场景:假设有数千人并发数据仓库,而其中100人的查询完全相同,从Hadoop的MapReduce基于数据流的角度讲,那么每个人都需要重新查询。因为基于数据流的方式不能够复用曾经的结果。但是Spark就可以避免,因为Spark可以对结果进行复用,(呵呵,MapReduce不服不行啊!)
好的,接下来我们在谈一下工作集:
工作集:曾经运行的工作,其他人在运行的话,不需要重新运行,而基于数据流需要重新运行(如果是Hadoop的话1000个人执行同样的查询,就需要重复执行1000次)。
注意:基于工作集的工作方式,即使结果放在磁盘上也是直接拿结果,不需要重新计算,只不过(Spark)现在是缓存在磁盘上而已,缓存在磁盘上比你直接在算一遍在放在磁盘上肯定要快,当然缓存多久看我们的运行了,我们当然可以将缓存清除掉:缓存随时可以清理掉,如果内存或磁盘不足就需要根据优先度将不常使用的缓存内容清理掉。
RDD的Cache是直接放在内存中的;最安全的措施就是Checkpoint,但是Checkpoint是重量级的:SparkStreaming经常要进行Checkpoint(Checkpoint一般就要放在磁盘嘛),原因是经常要用到以前的内容。
结论:Hadoop的MapReduce是基于数据集的工作方式,Spark(RDD)是基于工作集的工作方式,数据处理方式的不同,从先天上就导致了Spark相比于MapReduce具有巨大的优势。
呵呵,来张图恶搞一下:
无论是基于工作集的数据处理方式还是基于数据集的数据处理方式,这两种工作方式都有一些共同点:
1、都具有位置感知的特点:即数据在哪里,但是Spark的位置感知要比Hadoop的位置感知要好很多,Hadoop进行完partition之后就不管我们的Reducer在哪里了,但是Spark在进行下一个阶段的时候它会确定Reducer任务的位置,更精致化。(其实Spark的调度框架也是MapReduce的一种实现,只不过是更细致更高效)
对于上面这段话,我的理解就是对于Hadoop来说,Reducer任务的输入数据是通过网络从多个Mapper任务端远程拷贝过来的,不具有本地执行的性质,因此Reducer任务可以随意分配,但是Spark在分配Reducer任务的过程中,会更好的感知Reducer任务该分配到哪里,而不是像Hadoop那样随意。
2、都具有容错的特点,而常规的容错方式基本上分为两种:数据检查点CheckPoint和记录数据的更新。
数据检查点的基本的工作方式就是要通过数据中心的网络连接不同的机器,每次操作的时候都要复制整个数据集,就相当于每次都有一个拷贝,而拷贝是要走网络的,况且我们现在是分布式计算,所以数据检查点这种容错的方式显得更加致命。对于分布式应用程序来说,网络带宽本身就是分布式系统的瓶颈;另外因为每次都要拷贝,这个时候对重组资源也是一种非常大的消耗。
记录数据的更新:所谓数据记录更新就是每次数据变化的时候都作记录,这种方式不需要重新拷贝,但这种方式比较复杂,而且每次更新数据需要权限,容易失控、耗性能。
3、都具有负载均衡的特点
Spark中的RDD是基于工作集的应用抽象,本身除了具有位置感知、容错、负载均衡的特点之外,Spark中的RDD还增加了Resillient Distributed Dataset。
RDD的弹性表现为7个方面:
1、自动的进行内存和磁盘数据存储的切换
2、基于lineage(依赖,迭代)的高效容错
3.、task如果失败会自动进行特定次数的重试 (即失败了不立即就挂了,这也是弹性)
4、stage如果失败会自动进行特定次数的重试而且重试时只会试算失败的分片。
5、checkpoint(其实是一个重量级的操作,我们每次对RDD进行操作,一般都会采用新的RDD,当然除了最后一个Action触发作业以外,当然如果有的时候链条比较长或者计算比较笨重的时候,我们就考虑将数据都放在磁盘上,这就是checkpoint)和persist(在内存中或在磁盘中对数据进行复用,cache是persist的一种特殊情况),实际上这2个特点是效率和容错的延伸,同时也是复用方面的内容
6、数据调度弹性:DAG TASK和资源管理无关
7、数据分片的高度弹性(自由设置分片函数)即partition可伸缩。
我们在计算的过程中可能会产生很多数据碎片,这种时候一个Partition就会非常小,如果每个小Partition都消耗一个线程进行处理的话,就会降低处理效率。这种时候就可以考虑把小文件(小的partition)合并成一个大文件(较大的partition);另外一个方面,如果内存不多,而每个Partition数据比较大(比Block大),此时就可能考虑将数据变成更小的分片,此时尽管Spark将会出现更多的处理批次但是不会出现OOM。所以说通过改变数据分片的大小来提高并行度或降低并行度也是Spark高度弹性的表现。同时需要指出的是,不管是提高并行度还是降低并行度,在处理数据时仍具有数据本地性。当然,提高并行度还是降低度行度都是人工通过代码来调整的。
接下来我们谈一下Spark中RDD的本质:
Spark的每一步操作都是对RDD进行操作,而RDD是只读分区的集合,RDD本身就是一个数据的集合,可以简单将RDD理解为一个List或Array。用一句话概括:RDD是分布式函数式编程的抽象。
基于RDD的编程一般都是通过高阶函数的方式,之所以采用高阶函数是因为函数里面传函数要对我们当前的这个函数(如Map函数)作用的数据集进行每条记录的明细化操作,另外由于我们是分布式的集群,所以RDD叫做分布式函数式编程。
假设Spark有1000个RDD,一般不会产生中间结果,默认情况下只产生一次中间结果。为了不让其产生中间结果,就不能让他立即计算。而这就是lazy:不用时不算,用时才计算,所以不会产生中间结果。
RDD的核心之一就是它的Lazy级别,因为它不计算,开始的时候只是对数据的处理进行标记而已,比如我们的textFile根本就不从磁盘上读数据,map、flatmap其实并不计算数据,只是产生了操作的标记而已,只有触发的时候才计算。
由于Spark本身的RDD本身是只读的,为了应对计算模型,RDD又是lazy级别的。RDD每次操作都会产生新的RDD,每次构建新的RDD都是把父RDD作为第一个参数传入,这就构成了一个链条。在计算的最后Action才触发操作,这就构成了一个从后往前回溯的过程,其实就是函数展开的过程。
总结一下:RDD是lazy级别的且是不可变的,构成了链条,这种机制导致两点结果:
第一:计算的时候是从后往前回溯,不会每次计算的时候都会产生中间的计算结果。仅仅是记录了对其进行了
什么操作,即仅仅是一个标记。
第二:容错的时候会记录前面的东西,在前面某一个步骤的基础上,而不是从头开始算。
问题1:从第900步骤恢复的前提是要在第900步骤步骤持久化吗?
是的,需要在第900步骤持久化,或者说第900步骤是上一个Stage的结束,或者说第900步骤进行了checkPoint,或者进行了persist。即恢复点要么是checkpoint要么是前一个stage的结果(因为Stage结束时会自动写磁盘)
问题2:RDD是粗粒度的还是细粒度的呢?
所谓粗粒度就是每次操作的时候都作用于所有的数据集合。如果说更新粒度太细太多,记录成本就会非常高,效率就不会那么高。RDD的写操作或者改变操作都是粗粒度的。即我们所说的RDD是粗粒度的指的是RDD的写操作是粗粒度的,但是RDD的读操作既可以是粗粒度的又可以是细粒度的。(写操作就是修改数据,读就是查询数据),我们如果通过RDD读取数据,可以直接读取其中的一条记录(即读操作可以是细粒度的)。
问题3:RDD的缺陷
不支持细粒度的更新(写)操作和不支持增量迭代计算(如网络爬虫),即Spark框架本身不支持增量迭代计算,因为增量迭代的时候每次可能只迭代其中的一部分数据,但由于RDD本身是粗粒度的,不能很好的进行增量迭代。无法考虑是不是只是一部分数据。
OK,继续努力!