一、概述
1.轻:(1)采用语言简洁的scala编写;(2)利用了hadoop和mesos的基础设施
 
2.快:spark的内存计算、数据本地性和传输优化、调度优化,使其在迭代机器学习,ad-hoc query、图计算等方面是hadoop的MapReduce、hive和Pregel无法比拟的
 
3.灵:
(1)实现层:完美演绎了Scala trait动态混入策略(如可更换的集群调度器、序列化库);
(2)原语层:允许款站新的数据算子(operator)、新的数据源、新的language bindings;
(3)范式层:支持内存计算、多迭代批处理、即席查询、流处理和图计算等
 
4.巧:与Hadoop无缝结合;数据仓库实现上借了Hive的势;图计算借用Pregel和PowerGrah的API以及PowerGraph的点分割思想;最主要借助了scala
 
5.缺陷:细粒度、异步的数据处理支持差
 
二、Spark的依赖
1.Hadoop的MapReduce模型
2.Scala的函数式编程
3.两种种分布式存储系统:HDFS和S3,应该算是目前最主流的两种了。
 
三、计算范式和抽象
1.Spark是一种粗粒度数据并行的计算范式。数据并行的范式决定了 Spark无法完美支持细粒度、异步更新的操作;
 
2.Spark的RDD,采用Scala集合类型的编程风格。一是闭包,二是RDD的不可修改性。
 
3.Spark的计算抽象是带有工作集的数据流。工作集的抽象很普遍,如多 迭代机器学习、交互式数据挖掘和图计算;流处理是一种数据流模型,MapReduce也是,区别在于MapReduce需要在多次迭代中维护工作集。为保证容错,MapReduce采用了稳定存储(如HDFS)来承载工作集,代价是速度慢。HaLoop采用循环 敏感的调度器,保证前次迭代的Reduce输出和本次迭代的Map输入数据集在同一台物理机上,这样可以减少网络开销,但无法避免磁盘I/O的瓶颈。
 
4.Spark的突破在于,在保证容错的前提下,用内存来承载工作集。关键是实现容错,传统上有两种方法:日 志和检查点。考虑到检查点有数据冗余和网络通信的开销,Spark采用日志数据更新。Spark记录的是粗粒度的RDD更新,这样开销可以忽略不计。鉴于Spark的函数式语义和幂等特性,通过重放日志更新来容错,也不会有副作用。
 
四、编程模型
Transformations和Actions

对于RDD,有两种类型的动作,一种是Transformation,一种是Action。它们本质区别是:

  • Transformation返回值还是一个RDD。它使用了链式调用的设计模式,对一个RDD进行计算后,变换成另外一个RDD,然后这个RDD又可以进行另外一次转换。这个过程是分布式的
  • Action返回值不是一个RDD。它要么是一个Scala的普通集合,要么是一个值,要么是空,最终或返回到Driver程序,或把RDD写入到文件系统中

关于这两个动作,在Spark开发指南中会有就进一步的详细介绍,它们是基于Spark开发的核心。这里将Spark的官方ppt中的一张图略作改造,阐明一下两种动作的区别。

          图1 两个空间的切换,四类不同的RDD算子
输入算子(橘色箭头)将Scala集合类型或存储中的数据吸入RDD空间,转为RDD(蓝色实线框)。输入算子的输入大致有两类:一类针对Scala集合类型,如parallelize;另一类针对存储数据,如上例中的textFile。输入算子的输出就是Spark空间的RDD。

一部分变换算子视RDD的元素为简单元素,分为如下几类:

  • 输入输出一对一(element-wise)的算子,且结果RDD的分区结构不变,主要是map、flatMap(map后展平为一维RDD);
  • 输入输出一对一,但结果RDD的分区结构发生了变化,如union(两个RDD合为一个)、coalesce(分区减少);
  • 从输入中选择部分元素的算子,如filter、distinct(去除冗余元素)、subtract(本RDD有、它RDD无的元素留下来)和sample(采样)。

另一部分变换算子针对Key-Value集合,又分为:

  • 对单个RDD做element-wise运算,如mapValues(保持源RDD的分区方式,这与map不同);
  • 对单个RDD重排,如sort、partitionBy(实现一致性的分区划分,这个对数据本地性优化很重要,后面会讲);
  • 对单个RDD基于key进行重组和reduce,如groupByKey、reduceByKey;
  • 对两个RDD基于key进行join和重组,如join、cogroup。

后三类操作都涉及重排,称为shuffle类操作。

从RDD到RDD的变换算子序列,一直在RDD空间发生。这里很重要的设计是lazy evaluation:计算并不实际发生,只是不断地记录到元数据。元数据的结构是DAG(有向无环图),其中每一个“顶点”是RDD(包括生产该RDD 的算子),从父RDD到子RDD有“边”,表示RDD间的依赖性。Spark给元数据DAG取了个很酷的名字,Lineage(世系)。这个 Lineage也是前面容错设计中所说的日志更新。

Lineage一直增长,直到遇上行动(action)算子(图1中的绿色箭头),这时 就要evaluate了,把刚才累积的所有算子一次性执行。行动算子的输入是RDD(以及该RDD在Lineage上依赖的所有RDD),输出是执行后生 成的原生数据,可能是Scala标量、集合类型的数据或存储。当一个算子的输出是上述类型时,该算子必然是行动算子,其效果则是从RDD空间返回原生数据 空间。

行动算子有如下几类:生成标量,如count(返回RDD中元素的个数)、reduce、fold/aggregate(见 Scala同名算子文档);返回几个标量,如take(返回前几个元素);生成Scala集合类型,如collect(把RDD中的所有元素倒入 Scala集合类型)、lookup(查找对应key的所有值);写入存储,如与前文textFile对应的saveAsText-File。还有一个检 查点算子checkpoint。当Lineage特别长时(这在图计算中时常发生),出错时重新执行整个序列要很长时间,可以主动调用 checkpoint把当前数据写入稳定存储,作为检查点。

这里有两个设计要点。首先是lazy evaluation。熟悉编译的都知道,编译器能看到的scope越大,优化的机会就越多。Spark虽然没有编译,但调度器实际上对DAG做了线性复 杂度的优化。尤其是当Spark上面有多种计算范式混合时,调度器可以打破不同范式代码的边界进行全局调度和优化。下面的例子中把Shark的SQL代码 和Spark的机器学习代码混在了一起。各部分代码翻译到底层RDD后,融合成一个大的DAG,这样可以获得更多的全局优化机会。

另一个要点是一旦行动算子产生原生数据,就必须退出RDD空间。因为目前Spark只能够跟踪RDD的计算,原生数据的计算对它来说是不可见的(除非以后 Spark会提供原生数据类型操作的重载、wrapper或implicit conversion)。这部分不可见的代码可能引入前后RDD之间的依赖,如下面的代码:

第三行filter对errors.count()的依赖是由(cnt-1)这个原生数据运算产生的,但调度器看不到这个运算,那就会出问题了。

由于Spark并不提供控制流,在计算逻辑需要条件分支时,也必须回退到Scala的空间。由于Scala语言对自定义控制流的支持很强,不排除未来Spark也会支持。

Spark 还有两个很实用的功能。一个是广播(broadcast)变量。有些数据,如lookup表,可能会在多个作业间反复用到;这些数据比RDD要小得多,不 宜像RDD那样在节点之间划分。解决之道是提供一个新的语言结构——广播变量,来修饰此类数据。Spark运行时把广播变量修饰的内容发到各个节点,并保 存下来,未来再用时无需再送。相比Hadoop的distributed cache,广播内容可以跨作业共享。Spark提交者Mosharaf师从P2P的老法师Ion Stoica,采用了BitTorrent(没错,就是下载电影的那个BT)的简化实现。有兴趣的读者可以参考SIGCOMM'11的论文 Orchestra。另一个功能是Accumulator(源于MapReduce的counter):允许Spark代码中加入一些全局变量做 bookkeeping,如记录当前的运行指标。

五、运行和调度

Spark会将RDD和MapReduce函数,进行一次转换,变成标准的Job和一系列的Task。提交给SparkScheduler,SparkScheduler会把Task提交给Master,由Master分配给不同的Slave,最终由Slave中的Spark Executor,将分配到的Task一一执行,并且返回,组成新的RDD,或者直接写入到分布式文件系统。

1.由master完成的工作:
(1)记录变换算子序列,增量构建DAG图(有向无环图)
(2)行动算子触发,DAGSchedule将DAG图转化为作业和任务集
(3)由cluster manager将划分好分区的任务集发送到集群的节点上
 
2.由worker完成的工作:
(1)任务线程(task thread)真正运行DAGScheduler生成的任务;
(2)块管理器(block manager)负责与master上的block manager master通信(完美使用了Scala的Actor模式),为任务线程提供数据块。
 
3.DAGSchedule如何分区以及如何分配给集群上的节点
如何分区以及分区该放在哪个节点,涉及到了RDD的另外两个域,分别是分区划分器和首选位置
(1)分区划分器:Spark提供两种分区划分器:HashPartitioner和RangePartitioner。同时允许用户自定义ArrayHashPartitioner。
划分器的工作:它决定了该操作的父RDD和子RDD之间的依赖类型,这对于shuffle类操作很关键。同一个join算子,如果协同划分的话,两个父 RDD之间、父RDD与子RDD之间能形成一致的分区安排,即同一个key保证被映射到同一个分区,这样就能形成窄依赖。反之,如果没有协同划分,导致宽依赖。所谓协同划分,就是指定分区划分器以产生前后一致的分区安排。
 
(2)分区放置的节点,这关乎数据本地性:本地性好,网络通信就少。有些RDD产生时就有首选位置,如HadoopRDD分区的首选位置就是HDFS块所在的节点。有些RDD或分区被缓存了,那计算就应该送到缓存分区所在的节点进行。再不然,就回溯RDD的lineage一直找到具有首选位置属性的父RDD,并据此决定子RDD的放置。
 
RDD的数据结构里很重要的一个域是对父RDD的依赖。有两类依赖:窄(Narrow)依赖和宽(Wide)依赖。
注:这个概念我还没能够完全理解,以免误导,不做过多解释
宽/窄依赖的概念不止用在调度中,对容错也很有用。如果一个节点宕机了,而且运算是窄依赖,那只要把丢失的父RDD分区重算即可,跟其他节点没有依赖。而宽依赖需要父RDD的所有分区都存在, 重算就很昂贵了。所以如果使用checkpoint算子来做检查点,不仅要考虑lineage是否足够长,也要考虑是否有宽依赖,对宽依赖加检查点是最物 有所值的。

spark概论的更多相关文章

  1. spark概论,补充

    基本概念 RDD spark最大的亮点是提出RDD(Resilient Distributed Dataset)的概念,也就是可伸缩的分布式数据集合,本身只读,可恢复.spark本身不做物理储存,通过 ...

  2. 《spark快速大数据分析》

    第一 概论 1.spark的特点 适用多种不同分布式平台的场景,包括批处理,迭代算法,交互式查询,流处理: spark提供了python,scale,java等接口 2.spark的组件 spark的 ...

  3. SparkR(R on Spark)编程指南 含 dataframe操作 2.0

    SparkR(R on Spark)编程指南 Spark  2015-06-09 28155  1评论 下载为PDF    为什么不允许复制 关注iteblog_hadoop公众号,并在这里评论区留言 ...

  4. SparkR(R on Spark)编程指南 含 dataframe操作

    SparkR(R on Spark)编程指南 Spark  2015-06-09 28155  1评论 下载为PDF    为什么不允许复制 关注iteblog_hadoop公众号,并在这里评论区留言 ...

  5. Spark的job调优(1)

    本文翻译之cloudera的博客,本系列有两篇,第二篇看心情了 概论 当我们理解了transformation,action和rdd后,我们就可以写一些基础的spark的应用了,但是如果需要对应用进行 ...

  6. Spark踩坑记——Spark Streaming+Kafka

    [TOC] 前言 在WeTest舆情项目中,需要对每天千万级的游戏评论信息进行词频统计,在生产者一端,我们将数据按照每天的拉取时间存入了Kafka当中,而在消费者一端,我们利用了spark strea ...

  7. Spark RDD 核心总结

    摘要: 1.RDD的五大属性 1.1 partitions(分区) 1.2 partitioner(分区方法) 1.3 dependencies(依赖关系) 1.4 compute(获取分区迭代列表) ...

  8. spark处理大规模语料库统计词汇

    最近迷上了spark,写一个专门处理语料库生成词库的项目拿来练练手, github地址:https://github.com/LiuRoy/spark_splitter.代码实现参考wordmaker ...

  9. Hive on Spark安装配置详解(都是坑啊)

    个人主页:http://www.linbingdong.com 简书地址:http://www.jianshu.com/p/a7f75b868568 简介 本文主要记录如何安装配置Hive on Sp ...

随机推荐

  1. C Primer Plus(第五版)1

    这是C Primer Plus(第五版)的第一章,上传上来主要是方便我进行做笔记,写注释,还有我会删掉一些“废话”等. 1.1 C语言的起源 贝尔实验室的 Dennis Ritchie 在1972年开 ...

  2. Runtime机制之结构体及操作函数

    一.动态语言 Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理.这种动态语言的优势在于:具有灵活性,比如:消息转发,方法交换等.它有一个运行时系统Ob ...

  3. &&和||的那点事儿

    以前一直以为&&和||的运算结果就是布尔值,但今天看到一段代码又填补的一些知识漏洞. var a = (1&&2&&5) || 3; console.l ...

  4. Hadoop的奇技淫巧

    (2-6为性能优化)(7-9为函数介绍) 1.在JobHistory里面可以看到job相关的一些信息,用start-all启动Hadoop时便可以进入端口号8088查看查看信息,但是无法进入端口号19 ...

  5. 【PL/SQL练习】基本的PL/SQL语句

    1.无变量匿名快 begin dbms_output.put_line('Hello World'); end; 2.有变量的匿名块,定义变量: declare v_ename ); v_sal ,) ...

  6. 解决在 使用 AjaxFileUploder 插件时,不能获取返回的 json 结果数据

    在MVC  项目 中使用 AjaxFileUploader 这个插件时,在上传图片或文件时,在控制器中返回的是 json数据,可是在 ie,或 googleChrome 浏览器中却出现 返回的json ...

  7. 解决linux中Kipmi0进程对CPU使用率很高问题

    kipmi is supposed to run with low priority. When you say it consumes 70-90% of the CPUs, is that con ...

  8. ffmpeg视频格式转换(Java)

    命令: 高品质: ffmpeg -i E:\input\a.wmv -ab 128 -acodec libmp3lame -ac 1 -ar 22050 -r 29.97 -qscale 4 -y E ...

  9. 二模11day1解题报告

    T1.树的重量(weight) 给出一棵n个叶节点的树(但是有多组数据)以及n个节点之间的距离(最短距离...然而也只有一条路),求树的所有边权之和. 一开始完全没有思路啊...难道爆搜模拟??狂汗. ...

  10. Ossim主要功能实战

    Ossim主要功能实战 OSSIM通过将开源产品进行集成,从而提供一种能够实现安全监控功能的基础平台将Nagiso,Ntop,Snort,Nmap等开源工具集成在一起提供综合的安全保护功能,而不必在各 ...