Apache Spark是一个开源分布式运算框架,最初是由加州大学柏克莱分校AMPLab所开发。

Hadoop MapReduce的每一步完成必须将数据序列化写到分布式文件系统导致效率大幅降低。Spark尽可能地在内存上存储中间结果, 极大地提高了计算速度。

MapReduce是一路计算的优秀解决方案, 但对于多路计算的问题必须将所有作业都转换为MapReduce模式并串行执行。

Spark扩展了MapReduce模型,允许开发者使用有向无环图(DAG)开发复杂的多步数据管道。并且支持跨有向无环图的内存数据共享,以便不同的作业可以共同处理同一个数据

Spark不是Hadoop的替代方案而是其计算框架Hadoop MapReduce的替代方案。Hadoop更多地作为集群管理系统为Spark提供底层支持。

Spark可以使用本地Spark, Hadoop YARN或Apache Mesos作为集群管理系统。Spark支持HDFS,Cassandra, OpenStack Swift作为分布式存储解决方案。

Spark采用Scala语言开发运行于JVM上,并提供了Scala,Python, Java和R语言API,可以使用其中的Scala和Python进行交互式操作。

本文测试环境为Spark 2.1.0, Python API.

初识Spark

弹性分布式数据集(Resilient Distributed Dataset, RDD)是Saprk的基本数据结构, 代表可以跨机器进行分割的只读对象集合。

RDD可以由Hadoop InputFormats创建(比如HDFS上的文件)或者由其它RDD转换而来, RDD一旦创建便不可改变。RDD操作分为变换和行动两种:

  • 变换(Transformation): 接受一个RDD作为参数,返回一个新的RDD, 原RDD不变。

    包括:map,filter,flatMap,groupByKey,reduceByKey,aggregateByKey,pipe以及coalesce

  • 行动(Action): 接受一个RDD作为参数, 进行查询并返回一个值。

    包括: reduce,collect,count,first,take,countByKey以及foreach

Spark的核心组件包括:

  • Spark Core: 核心功能, 提供RDD及其API和操作。

  • Spark SQL: 提供通过Apache Hive的SQL变体HiveQL与Spark进行交互的API。每个数据表被当做一个RDD,Spark SQL查询被转换为Spark操作。

  • Spark Streaming:允许对实时数据流进行处理和控制,park Streaming允许程序能够像普通RDD一样处理实时数据。

  • MLlib:一个常用机器学习算法库,算法被实现为对RDD的Spark操作。这个库包含可扩展的学习算法,比如分类、回归等需要对大量数据集进行迭代的操作

  • GraphX: 图计算框架, GraphX扩展了RDD API,包含控制图、创建子图、访问路径上所有顶点的操作。

体验Spark

对于Linux和Mac用户只需要在本地安装java运行环境并在官网中下载Pre-built版本的压缩包, 解压缩之后即可以单机模式使用Spark。

进入解压后的spark目录, 其中包含一些脚本和二进制程序:

  • sbin: 管理员命令目录

    • spark-config.sh 将spark运行配置写入环境变量
    • spark-daemon.sh 在本地启动守护进程
    • spark-daemons.sh 在所有slave主机上启动守护进程
    • start-master.sh 启动master进程
    • start-slave.sh 在本地上启动slave进程
    • start-slaves.sh 根据conf/slaves配置文件在slave主机上启动slave进程
    • start-all.sh 启动所有守护进程,启动本地master进程, 根据conf/slaves启动slave进程
    • stop-all.sh 停止所有守护进程及其下的master/slave进程
    • stop-master.sh 停止master进程
    • stop-slave.sh 停止本地的slave进程
    • stop-slaves.sh 停止所有slave进程
    • 其它服务控制脚本
  • bin 普通用户工具目录
    • pyspark: python交互环境
    • spark-shell scala交互环境
    • sparkR R交互环境
    • spark-submit将Spark应用提交到集群上运行
    • spark-sql spark-sql交互环境
    • run-example 运行示例

使用pyspark交互界面

使用sbin/start-all.sh启动spark然后调用bin/pyspark进入Python交互界面:

SparkSession和SparkContext初始化成功后, 可以确认交互界面已正确启动。

>>> txt = sc.textFile("README.md")
>>> txt.count()
104

上述代码中,sc是SparkContext的别名, 我们根据"README.md"的内容创建了一个RDD并用count()方法取出RDD中项目的数量。

使用spark-submit提交python作业

bin/spark-submit可以将使用python编写的Spark应用提交到集群上运行。

我们将上文中的示例写成脚本, 与交互模式不同的是脚本需要手动进行一些配置:

from pyspark import SparkConf, SparkContext

APP_NAME = "My Spark Application"
MASTER_URL = "local[*]" conf = SparkConf().setAppName(APP_NAME)
conf = conf.setMaster(MASTER_URL)
sc = SparkContext(conf=conf) def main(sc):
txt = sc.textFile("README.md")
print(txt.count()) if __name__ == '__main__':
main(sc)

保存为my_test.py, 使用spark-submit提交作业:

$ bin/spark-submit my_test.py
104

现在对上述代码做一些说明。

APP_NAME是应用的名称由程序员自定义,MASTER_URL用于指定集群Master的位置:

URL 含义
local 用一个worker线程本地运行Spark
local[K] 用k个worker线程本地运行Spark(通常设置为机器核心数)
local[*] 用尽可能多的worker线程本地运行Spark
spark://HOST:PORT 连接到给定的Spark独立部署集群master, 默认端口7077
mesos://HOST:PORT 连接到给定的mesos集群
yarn-client 以client模式连接到Yarn集群。集群位置将基于通过HADOOP_CONF_DIR变量找到
yarn-cluster 以cluster模式连接到Yarn集群。群集位置将基于通过HADOOP_CONF_DIR变量找到

RDD基本操作

创建RDD

并行集合(Parallelized collections)基于python可迭代对象(iterable)创建:

>>> data = [1,2,3,4]
>>> para_data = sc.parallelize(data)
>>> para_data
ParallelCollectionRDD[0] at parallelize at PythonRDD.scala:475
>>> para_data.reduce(lambda x, y: x+y)
10

RDD一旦创建即可以并行模式运算.

除了使用内部的iterable对象创建RDD外, 也可以使用外部数据源创建RDD.

Spark 可以从任何一个 Hadoop 支持的存储源创建分布式数据集,包括你的本地文件系统,HDFS,Cassandra,HBase等.

>>> src_uri = "README.md"
>>> txt = sc.textFile(src_uri)
>>> txt.count()
104

Spark支持textFile, SequenceFile和其它Hadoop InputFormat作为外部数据源。

src_uri支持的协议包括hdfs://, s3n://file://等。直接填写路径则默认采用file://即本地文件系统路径.

如果src_uri使用本地文件系统路径,文件必须能在 worker 节点上用相同的路径访问到。要么复制文件到所有的 workers,要么使用网络共享文件系统.

操作RDD

Spark采用惰性求值的机制进行运算, 我们用一个简单的例子说明Spark的运算过程:

lines = sc.textFile("data.txt")
lineLengths = lines.map(lambda s: len(s))
totalLength = lineLengths.reduce(lambda a, b: a + b)

第一行从外部数据集创建了一个名为lines的RDD, lines只是一个指针文件内容没有真的被读入内存。

第二行执行了map操作, 同样的lineLength并没有被立即求值。

第三行执行了reduce操作, Spark 把计算分成多个任务(task),并且让它们运行在多个机器上。每台机器都运行自己的 map 部分和本地 reduce 部分, 并把结果返回给Master。

transformation

前文已经说明transformation是根据RDD创建新的RDD的操作,这里将说明一些常用的操作,更多内容请参见官方文档.

  • rdd.map(func): 将数据源的每个元素传递给func函数, 得到func的返回值组成新RDD

    在示例lines.map(lambda s: len(s)) 中lines的元素类型为str, map函数将其映射为长度元素长度的集合。

  • rdd.flatMap(func): func接受一个元素为参数,返回一个可迭代对象。对rdd中所有元素应用func函数, 将返回的列表合并为新的RDD。

  >>> r = sc.parallelize([1,2,3,4]).flatMap(lambda x: [x, x+1])
>>> r.collect() # show all elements
>>> [1, 2, 2, 3, 3, 4, 4, 5]
  • rdd.filter(func): 将数据源的每个元素传递给func函数, 使func返回True的元素加入到结果RDD中

  • rdd1.union(rdd2): 求rdd1与rdd2的并集

  • rdd1.intersection(rdd2): 求rdd1和rdd2的交集

  • rdd.distinct(): 返回去除重复元素后的rdd

action

action是对RDD进行查询并返回单个元素的操作, 这里将说明一些常用的操作,更多内容请参见官方文档

  • rdd.reduce(func): func是接受两个参数并返回一个值的函数, reduce使用func对集合进行聚合。

    这个过程可以理解为从集合中任取两个元素传给func, 然后将返回值加入集合中并删除两个参数, 反复迭代直至集合只有一个元素, 该元素即为最后的返回值。

    示例lineLengths.reduce(lambda a, b: a + b) 中, reduce函数对RDD内所有函数进行了求和。

  • rdd.collect(): 以python list的形式返回集合中所有元素

  • rdd.first(): 返回集合中第一个元素, 对集合不产生影响

  • rdd.take(n): 返回集合中前n个元素组成的list, 下标从1开始

  • rdd.count(): 返回集合中元素的数目

  • rdd.foreach(func): func是接受一个参数的函数, 对集合中每个元素调用func函数, foreach返回None

使用键值对

上文中的RDD对元素的类型是基本没有限制的, 类似于python内置的list(其实更类似于ORM的查询集)。RDD在使用二元组作为元素时, Spark会将二元组作为一个键值对处理, 二元组的第一个元素被认为是键, 第二个元素认为是值。

元素为二元组的RDD仍然可以使用普通RDD的操作,Spark也为这类RDD定义了一些基于键值对的操作:

  • groupByKey():将key相同的键值对合并为一个键值对: (key,[val, val, ...])

  • reduceByKey(func): 对key相同的键值对应用func进行聚合: (key,RDD<val>.reduce(func))

  • ​rdd.sortByKey(ascending=True): 按key对键值对进行排序,默认为升序

  • rdd1.join(rdd2): 对两个键值对形式的rdd进行合并,(k, v)和(k,w)将被合并为(k, (v,w))

  • countByKey(): 返回每个键对应键值对的个数(key, count), 返回值为dict而非RDD.

RDD持久化

RDD持久化是Spark的一个重要功能, 上文已经提及Spark提供了持久化到内存的功能极大的提高了运算速度, 也是Spark比Hadoop MapReduce更先进的原因之一。

rdd.persist([level])可以根据指定等级执行持久化:

>>> from pyspark import StorageLevel
>>> r.persist(StorageLevel.MEMORY_ONLY)
PythonRDD[16]

Spark支持的持久化级别包括:

  • MEMORY_ONLY: 将RDD作为java对象存储在JVM中,若RDD的某部分无法作为java对象存储,则不对该部分进行缓存。默认缓存级别。

  • MEMORY_AND_DISK: 将RDD作为java对象存储在JVM中,若RDD的某部分无法作为java对象存储,则将该部分用pickle序列化后缓存到磁盘上。

  • MEMORY_ONLY_SER: 将RDD序列化后作为java byte[]存储在内存中,不合适的分区不缓存。 比较节省内存但是消耗时间

  • MEMORY_AND_DISK_SER: 将RDD序列化后作为java byte[]存储在内存中,不合适的分区序列化后存储到磁盘上

  • DISK_ONLY: 序列化后仅存储在磁盘上

  • MEMORY_ONLY_2, MEMORY_AND_DISK_2等: 与上述存储级别类似, 不过是存储到两个节点上

  • OFF_HEAP: 将RDD序列化后缓存到分布式内存存储Tachyon上

Spark官方文档给出了一些关于选择存储级别的建议:

  • 如果你的RDD适合默认的存储级别(MEMORY_ONLY),就选择默认的存储级别。因为这是cpu利用率最高的选项,会使RDD上的操作尽可能的快。

  • 如果不适合用默认的级别,选择MEMORY_ONLY_SER。选择一个更快的序列化库提高对象的空间使用率,但是仍能够相当快的访问。

  • 除非函数计算RDD的花费较大或者它们需要过滤大量的数据,不要将RDD存储到磁盘上,否则,重复计算一个分区就会和重磁盘上读取数据一样慢。

  • 如果你希望更快的错误恢复,可以利用重复(replicated)存储级别。所有的存储级别都可以通过重复计算丢失的数据来支持完整的容错,但是重复的数据能够使你在RDD上继续运行任务,而不需要重复计算丢失的数据。

  • 在拥有大量内存的环境中或者多应用程序的环境中,OFF_HEAP具有如下优势:

    • 它运行多个执行者共享Tachyon中相同的内存池
    • 它显著地减少垃圾回收的花费
    • 如果单个的执行者崩溃,缓存的数据不会丢失

Spark提供了rdd.cache()方法, 它与rdd.persist(StorageLevel.MEMORY_ONLY)功能相同。

Spark自动的监控每个节点缓存的使用情况,利用最近最少使用原则删除老旧的数据。rdd.unpersist()可以手动删除缓存。

使用共享变量

一个传递给Spark操作(例如map和reduce)的函数在远程节点上面运行时,Spark操作实际上操作的是这个函数所用变量的一个独立副本。

这些变量被复制到每台机器上,并且这些变量在远程机器上 的所有更新都不会传递回驱动程序,通常这种跨任务的读写变量是低效的。

Spark提供了两个共享变量: 广播变量(broadcast variable)和累加器(accumulator)进行跨任务共享。

广播变量

广播变量在每台机器上面缓存一个只读变量,而不是每个任务保存一个副本。Spark也尝试着利用有效的广播算法去分配广播变量,以减少通信的成本。

>>> broadcastVar = sc.broadcast([1, 2, 3])
>>> broadcastVar.value
[1, 2, 3]

广播变量创建后我们可以使用它代替原变量,其操作与RDD基本相同。

累加器

累加器特性与广播变量类似, 另外定义了add方法用于累加。

>>> accum = sc.accumulator(0)
>>> accum
Accumulator<id=0, value=0>
>>> sc.parallelize([1, 2, 3, 4]).foreach(lambda x: accum.add(x))
>>> accum.value
10

累加器默认使用python内置int类型计数, 我们可以自定义计数类型。通常自定义类型为多维向量,用来进行复杂计数。


分布式计算框架Spark的更多相关文章

  1. 分布式计算框架-Spark(spark环境搭建、生态环境、运行架构)

    Spark涉及的几个概念:RDD:Resilient Distributed Dataset(弹性分布数据集).DAG:Direct Acyclic Graph(有向无环图).SparkContext ...

  2. 如何在spark中读写cassandra数据 ---- 分布式计算框架spark学习之六

    由于预处理的数据都存储在cassandra里面,所以想要用spark进行数据分析的话,需要读取cassandra数据,并把分析结果也一并存回到cassandra:因此需要研究一下spark如何读写ca ...

  3. Hadoop 三剑客之 —— 分布式计算框架 MapReduce

    一.MapReduce概述 二.MapReduce编程模型简述 三.combiner & partitioner 四.MapReduce词频统计案例         4.1 项目简介      ...

  4. Hadoop 学习之路(三)—— 分布式计算框架 MapReduce

    一.MapReduce概述 Hadoop MapReduce是一个分布式计算框架,用于编写批处理应用程序.编写好的程序可以提交到Hadoop集群上用于并行处理大规模的数据集. MapReduce作业通 ...

  5. Hadoop 系列(三)—— 分布式计算框架 MapReduce

    一.MapReduce概述 Hadoop MapReduce 是一个分布式计算框架,用于编写批处理应用程序.编写好的程序可以提交到 Hadoop 集群上用于并行处理大规模的数据集. MapReduce ...

  6. 大数据时代之hadoop(五):hadoop 分布式计算框架(MapReduce)

    大数据时代之hadoop(一):hadoop安装 大数据时代之hadoop(二):hadoop脚本解析 大数据时代之hadoop(三):hadoop数据流(生命周期) 大数据时代之hadoop(四): ...

  7. 分布式计算框架学习笔记--hadoop工作原理

    (hadoop安装方法:http://blog.csdn.net/wangjia55/article/details/53160679这里不再累述) hadoop是针对大数据设计的一个计算架构.如果你 ...

  8. hadoop-MapReduce分布式计算框架

    计算框架: MapReduce:主要用于离线计算 Storm:流式计算框架,更适合做实时计算 stack:内存计算框架,快速计算 MapReduce设计理念: --何为分布式计算 --移动计算,而不是 ...

  9. VM Depot 分布式计算框架主题应用精选

     发布于 2014-12-24 作者 陈 忠岳 在前几期为各位介绍了大数据应用主题以及开发运营主题的各类镜像后,这次我们精选了 VM Depot 站点中分布式计算相关主题的虚拟机镜像和大家一起分享 ...

随机推荐

  1. GBDT(MART) 迭代决策树详解

    在网上看到一篇对从代码层面理解gbdt比较好的文章,转载记录一下: GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Re ...

  2. vue全局后置钩子afterEach

    beforeEach是路由跳转前执行的,afterEach是路由跳转后执行的. afterEach只有两个参数  afterEach((to,from)=>{}) 例子: router.afte ...

  3. app已损坏,打不开。你应该将它移到废纸篓

    首先声明: 有可能并非你安装的软件已损坏,而是Mac系统的安全设置问题,因为这些应用都是破解或者汉化的,那么解决方法就是临时改变Mac系统安全设置. 出现这个问题的解决方法: 修改系统配置:系统偏好设 ...

  4. Android开发之Activity

    活动(Activity) 活动是最容易吸引用户的地方,它是一种可以包含用户界面的组件,主要用于和用户交互. FirstActivity 手动创建活动 新建一个project,不再选择empty act ...

  5. 20155326刘美岑 《网络对抗》Exp2 后门原理与实践

    20155326刘美岑 <网络对抗>Exp2 后门原理与实践 实验内容 (1)使用netcat获取主机操作Shell,cron启动 (2)使用socat获取主机操作Shell, 任务计划启 ...

  6. tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...

  7. 使用Python对Twitter进行数据挖掘(Mining Twitter Data with Python)

    目录 1.Collecting data 1.1 Register Your App 1.2 Accessing the Data 1.3 Streaming 2.Text Pre-processin ...

  8. [Project] SpellCorrect源码详解

    该Project原来的应用场景是对电商网站中输入一个错误的商品名称进行智能纠错,比如iphoae纠错为iphone.以下介绍的这个版本对其作了简化,项目源代码地址参见我的github:https:// ...

  9. 源设置导致Docker镜像构建失败

    编写了一个Dockerfile,主要目的是构建一个镜像,镜像默认安装了openjdk-1.8-jre,还有另外一些包(这些包里面有dev版本的,也有release版本的),Dockerfile的内容大 ...

  10. Codeforces Round #525 (Div. 2) E. Ehab and a component choosing problem 数学

    题意:给出树 求最大的sigma(a)/k k是选取的联通快个数   联通快不相交 思路: 这题和1个序列求最大的连续a 的平均值  这里先要满足最大平均值  而首先要满足最大  也就是一个数的时候可 ...