spark快速数据分析
Spark是类似于Hadoop的开源集群计算环境,但是它具有一些有用的区别,使其在某些工作负载中更具优势-即,Spark启用了内存中分布式数据集,该数据集除了交互式查询外还优化了迭代工作负载。
Spark是用Scala语言实现的,并使用Scala作为其应用程序框架。 与Hadoop不同,Spark和Scala创建了紧密的集成,其中Scala可以轻松地将分布式数据集作为本地集合对象进行操作。
尽管创建Spark是为了支持分布式数据集上的迭代作业,但实际上它是对Hadoop的补充,可以在Hadoop文件系统上并行运行。 通过称为Mesos的第三方群集框架,可以支持此行为。 Spark是在加利福尼亚大学伯克利分校的算法,机器和人员实验室开发的,用于构建大规模和低延迟的数据分析应用程序。
Spark集群计算架构
尽管Spark与Hadoop有相似之处,但它代表了一个新的群集计算框架,但有许多有用的区别。 首先,Spark是为集群计算中的特定类型的工作负载而设计的,即,这些工作负载跨并行操作重用了一组工作数据(例如机器学习算法)。 为了针对这些类型的工作负载进行优化,Spark引入了内存中群集计算的概念,可以在其中将数据集缓存在内存中以减少其访问延迟。
Spark还引入了称为弹性分布式数据集 (RDD)的抽象。 RDD是分布在一组节点上的对象的只读集合。 这些集合具有弹性,因为如果丢失一部分数据集,则可以重建它们。 重建一部分数据集的过程依赖于维持沿袭 (或允许基于导出数据的过程来重新创建一部分数据集的信息)的容错机制。 RDD表示为Scala对象,可以从文件创建; 作为并行切片(分布在节点上); 作为另一个RDD的转换; 最后,通过更改现有RDD的持久性,例如请求将其缓存在内存中。
Spark中的应用程序称为驱动程序,这些驱动程序实现在单个节点上执行或在一组节点上并行执行的操作。 与Hadoop一样,Spark支持单节点群集或多节点群集。 对于多节点操作,Spark依赖于Mesos群集管理器。 Mesos为分布式应用程序的资源共享和隔离提供了一个有效的平台(请参见图1 )。 此设置允许Spark在单个共享节点池中与Hadoop共存。
图1. Spark依靠Mesos集群管理器进行资源共享和隔离。
Spark编程模型
驱动程序可以对数据集执行两种类型的操作:动作和转换。 动作对数据集执行计算,然后将值返回给驱动程序; 转换将根据现有数据集创建一个新数据集。 动作示例包括执行Reduce操作(使用函数)和迭代数据集(在每个元素上运行函数,类似于Map操作)。 转换的示例包括Map操作和Cache操作(要求将新数据集存储在内存中)。
我们将很快看一下这两个操作的示例,但首先,让我们熟悉Scala语言。
Scala简介
Scala可能是互联网上保存最完好的秘密之一。 您可以在Internet上一些最繁忙的网站(包括Twitter,LinkedIn和Foursquare)(其Web应用程序框架称为Lift )中找到正在生产的Scala。 还有证据表明,金融机构对Scala的表现产生了兴趣(例如EDF Trading对衍生产品定价的使用)。
Scala是一种多范式语言,因为它以平滑和舒适的方式支持与命令式,功能性和面向对象的语言相关的语言功能。 从面向对象的角度来看,Scala中的每个值都是一个对象。 同样,从功能的角度来看,每个功能都是一个值。 Scala还使用具有表现力和安全性的类型系统进行静态类型化。
另外,Scala是一种虚拟机(VM)语言,并通过Scala编译器生成的字节码,使用Java Runtime Environment版本2在Java™虚拟机(JVM)上直接运行。 此设置允许Scala几乎在JVM运行的任何地方运行(需要额外的Scala运行时库)。 它还使Scala可以利用现有的Java库的庞大目录以及现有的Java代码。
最后,Scala是可扩展的。 该语言(实际上代表可扩展语言 )是为简单扩展定义的,这些扩展可以完全集成到该语言中。
Scala说明
让我们来看一些使用Scala语言的示例。 Scala带有自己的解释器,可让您以交互方式尝试该语言。 斯卡拉的一个有用的讨论已经超出了本文的范围,但你可以找到更多信息的链接相关主题 。
清单1通过其解释器开始了Scala语言的快速浏览。 启动Scala后,您将看到它的提示,通过它可以交互式地评估表达式和程序。 首先创建两个变量-一个是不可变的( vals
,称为单赋值 ),另一个是可变的( vars
)。 请注意,当您尝试更改b
(您的var
)时,您可以成功,但是当您尝试更改为val
时会返回错误。
清单1. Scala中的简单变量
$ scala
Welcome to Scala version 2.8.1.final (OpenJDK Client VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a = 1
a: Int = 1
scala> var b = 2
b: Int = 2
scala> b = b + a
b: Int = 3
scala> a = 2
<console>6: error: reassignment to val
a = 2
^
接下来,创建一个简单的方法来计算并返回Int
的平方。 在Scala中定义方法以def
开头,后跟方法名称和参数列表,然后将其设置为语句数(在此示例中为一个)。 未指定返回值,因为可以从方法本身推断出该值。 请注意,这与为变量分配值相似。 我将在名为3
的对象和名为res0
的结果变量(Scala解释器自动为您创建)的结果上演示该过程。 清单2中全部显示了这些内容。
清单2. Scala中的一种简单方法
scala> def square(x: Int) = x*x
square: (x: Int)Int
scala> square(3)
res0: Int = 9
scala> square(res0)
res1: Int = 81
接下来,让我们看一下Scala中一个简单类的构造(请参见清单3 )。 您定义一个简单的Dog
类,该类接受一个String
参数(您的名称构造函数)。 请注意,该类直接采用参数(在类的主体中没有定义类参数)。 存在一个被调用时发出字符串的方法。 您创建您的类的新实例,然后调用您的方法。 请注意,解释器会插入竖线:它们不是代码的一部分。
清单3. Scala中的一个简单类
scala> class Dog( name: String ) {
| def bark() = println(name + " barked")
| }
defined class Dog
scala> val stubby = new Dog("Stubby")
stubby: Dog = Dog@1dd5a3d
scala> stubby.bark
Stubby barked
scala>
完成后,只需键入:quit
即可退出Scala解释器。
安装Scala和Spark
第一步是下载和配置Scala。 清单4中显示的命令说明了如何下载和准备Scala安装。 使用2.8版本的Scala,因为这是Spark记录为需要的内容。
清单4.安装Scala
$ wget http://www.scala-lang.org/downloads/distrib/files/scala-2.8.1.final.tgz
$ sudo tar xvfz scala-2.8.1.final.tgz --directory /opt/
为了使Scala可见,请将以下行添加到您的.bashrc中(如果您使用的是Bash作为外壳程序):
export SCALA_HOME=/opt/scala-2.8.1.final
export PATH=$SCALA_HOME/bin:$PATH
然后,您可以测试安装,如清单5所示 。 这组命令将更改加载到bashrc文件,然后对Scala解释器外壳进行快速测试。
清单5.配置和运行交互式Scala
$ scala
Welcome to Scala version 2.8.1.final (OpenJDK Client VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> println("Scala is installed!")
Scala is installed!
scala> :quit
$
如图所示,您现在应该看到一个Scala提示符。 您可以输入:quit
。 请注意,Scala在JVM上下文中执行,因此您也将需要它。 我使用的是Ubuntu,默认情况下是OpenJDK附带的。
接下来,获取Spark框架的最新副本。 为此,请使用清单6中所示的脚本。
清单6.下载和安装Spark框架
wget https://github.com/mesos/spark/tarball/0.3-scala-2.8/
mesos-spark-0.3-scala-2.8-0-gc86af80.tar.gz
$ sudo tar xvfz mesos-spark-0.3-scala-2.8-0-gc86af80.tar.gz
接下来,在./conf/spar-env.sh中使用Scala主目录的以下行设置spark配置:
export SCALA_HOME=/opt/scala-2.8.1.final
设置的最后一步是使用简单的构建工具( sbt
)更新您的发行sbt
。 sbt
是Scala的构建工具,已与Spark发行版一起使用。 您在mesos-spark-c86af80子目录中执行更新和编译步骤,如下所示:
$ sbt/sbt update compile
请注意,执行此步骤时需要连接到Internet。 完成后,对Spark进行快速测试,如清单7所示。 在此测试中,您要求运行SparkPi示例,该示例计算pi的估计值(通过在单位平方中进行随机点采样)。 显示的格式要求示例程序(spark.examples.SparkPi)和host参数,该参数定义Mesos主节点(在本例中为localhost,因为它是单节点群集),以及要使用的线程数。 注意,在清单7中 ,执行了两个任务,但是它们被序列化了(任务0开始并在任务1开始之前完成)。
清单7.对Spark进行快速测试
$ ./run spark.examples.SparkPi local[1]
11/08/26 19:52:33 INFO spark.CacheTrackerActor: Registered actor on port 50501
11/08/26 19:52:33 INFO spark.MapOutputTrackerActor: Registered actor on port 50501
11/08/26 19:52:33 INFO spark.SparkContext: Starting job...
11/08/26 19:52:33 INFO spark.CacheTracker: Registering RDD ID 0 with cache
11/08/26 19:52:33 INFO spark.CacheTrackerActor: Registering RDD 0 with 2 partitions
11/08/26 19:52:33 INFO spark.CacheTrackerActor: Asked for current cache locations
11/08/26 19:52:33 INFO spark.LocalScheduler: Final stage: Stage 0
11/08/26 19:52:33 INFO spark.LocalScheduler: Parents of final stage: List()
11/08/26 19:52:33 INFO spark.LocalScheduler: Missing parents: List()
11/08/26 19:52:33 INFO spark.LocalScheduler: Submitting Stage 0, which has no missing ...
11/08/26 19:52:33 INFO spark.LocalScheduler: Running task 0
11/08/26 19:52:33 INFO spark.LocalScheduler: Size of task 0 is 1385 bytes
11/08/26 19:52:33 INFO spark.LocalScheduler: Finished task 0
11/08/26 19:52:33 INFO spark.LocalScheduler: Running task 1
11/08/26 19:52:33 INFO spark.LocalScheduler: Completed ResultTask(0, 0)
11/08/26 19:52:33 INFO spark.LocalScheduler: Size of task 1 is 1385 bytes
11/08/26 19:52:33 INFO spark.LocalScheduler: Finished task 1
11/08/26 19:52:33 INFO spark.LocalScheduler: Completed ResultTask(0, 1)
11/08/26 19:52:33 INFO spark.SparkContext: Job finished in 0.145892763 s
Pi is roughly 3.14952
$
通过增加线程数,您不仅可以增加线程执行的并行度,而且可以在更短的时间内执行作业(如清单8所示)。
清单8.使用两个线程对Spark进行另一个快速测试
$ ./run spark.examples.SparkPi local[2]
11/08/26 20:04:30 INFO spark.MapOutputTrackerActor: Registered actor on port 50501
11/08/26 20:04:30 INFO spark.CacheTrackerActor: Registered actor on port 50501
11/08/26 20:04:30 INFO spark.SparkContext: Starting job...
11/08/26 20:04:30 INFO spark.CacheTracker: Registering RDD ID 0 with cache
11/08/26 20:04:30 INFO spark.CacheTrackerActor: Registering RDD 0 with 2 partitions
11/08/26 20:04:30 INFO spark.CacheTrackerActor: Asked for current cache locations
11/08/26 20:04:30 INFO spark.LocalScheduler: Final stage: Stage 0
11/08/26 20:04:30 INFO spark.LocalScheduler: Parents of final stage: List()
11/08/26 20:04:30 INFO spark.LocalScheduler: Missing parents: List()
11/08/26 20:04:30 INFO spark.LocalScheduler: Submitting Stage 0, which has no missing ...
11/08/26 20:04:30 INFO spark.LocalScheduler: Running task 0
11/08/26 20:04:30 INFO spark.LocalScheduler: Running task 1
11/08/26 20:04:30 INFO spark.LocalScheduler: Size of task 1 is 1385 bytes
11/08/26 20:04:30 INFO spark.LocalScheduler: Size of task 0 is 1385 bytes
11/08/26 20:04:30 INFO spark.LocalScheduler: Finished task 0
11/08/26 20:04:30 INFO spark.LocalScheduler: Finished task 1
11/08/26 20:04:30 INFO spark.LocalScheduler: Completed ResultTask(0, 1)
11/08/26 20:04:30 INFO spark.LocalScheduler: Completed ResultTask(0, 0)
11/08/26 20:04:30 INFO spark.SparkContext: Job finished in 0.101287331 s
Pi is roughly 3.14052
$
使用Scala构建一个简单的Spark应用程序
要构建Spark应用程序,您需要在单个Java存档(JAR)文件中使用Spark及其依赖项。 使用sbt
在Spark的顶级目录中创建此JAR:
$ sbt/sbt assembly
结果是文件./core/target/scala_2.8.1/"Spark Core-assembly-0.3.jar“)。 将此文件添加到您的CLASSPATH中,以便可以访问。 在此示例中,您将不会使用此JAR,因为它将与Scala解释器一起运行而不是对其进行编译。
对于此示例,使用标准的MapReduce转换(如清单9所示)。 该示例从Spark类的必要导入开始。 接下来,使用主方法定义类( SparkTest
),该类将解析参数以供以后使用。 这些参数定义了执行Spark的环境(在这种情况下,是单节点群集)。 接下来,创建您的SparkContext
对象,该对象告诉Spark如何访问您的集群。 该对象需要两个参数:Mesos主名称(传入)和您分配作业的名称( SparkTest
)。 从命令行解析切片的数量,这告诉Spark作业使用多少个线程。 剩下的最后一项设置是指定要用于MapReduce操作的文本文件。
最后,您将了解Spark示例的真实内容,该示例包含一组转换。 对于您的文件,调用flatMap
方法以返回RDD(通过指定的函数将文本行拆分为标记)。 然后,此RDD通过map
方法(创建键值对) ReduceByKey
,最后通过ReduceByKey
方法ReduceByKey
,该方法聚合您的键值对。 它通过将键值对传递给_ + _
匿名函数来实现。 此函数仅采用两个参数(键和值),然后将它们附加在一起以返回结果(一个String
和一个Int
)。 然后,此值作为文本文件发出(到输出目录)。
清单9. Scala / Spark中的MapReduce(SparkTest.scala)
import spark.SparkContext
import SparkContext._
object SparkTest {
def main( args: Array[String]) {
if (args.length == 0) {
System.err.println("Usage: SparkTest <host> [<slices>]")
System.exit(1)
}
val spark = new SparkContext(args(0), "SparkTest")
val slices = if (args.length > 1) args(1).toInt else 2
val myFile = spark.textFile("test.txt")
val counts = myFile.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
counts.saveAsTextFile("out.txt")
}
}
SparkTest.main(args)
要执行脚本,只需使用以下命令请求执行:
$ scala SparkTest.scala local[1]
您可以在输出目录(作为output / part-00000)中找到MapReduce测试文件。
其他大数据分析框架
自从Hadoop开发以来,其他许多大数据分析平台也已出现,值得一看。 这些平台的范围从基于脚本的简单产品到类似于Hadoop的生产环境。
最简单的一种叫做bashreduce
,顾名思义,它允许您在Bash环境中的多台计算机上执行MapReduce类型的操作。 bashreduce
依赖于计划使用的计算机集群的安全外壳(无密码),然后作为脚本存在,您可以通过脚本通过UNIX®风格的工具( sort
, awk
, netcat
等)来请求作业。
GraphLab是MapReduce抽象的另一个有趣的实现,它专注于机器学习算法的并行实现。 在GraphLab中,Map阶段定义可以独立地(在单独的主机上)独立执行的计算,而Reduce阶段将结果组合在一起。
最后,来自Twitter的Storm(通过收购BackType)是大数据领域的一个新来者。 Storm被定义为“实时处理的Hadoop”,并且专注于流处理和连续计算(计算出流结果时)。 Storm用Clojure(Lisp语言的现代方言)编写,但是支持以任何语言(例如Ruby和Python)编写的应用程序。 Twitter于2011年9月将Storm开源。
请参阅相关主题以获取更多信息。
更进一步
Spark是不断壮大的大数据分析解决方案家族的有趣补充。 它不仅为处理分布式数据集提供了一个有效的框架,而且以一种有效的方式(通过简单干净的Scala脚本)提供了这种框架。 Spark和Scala都在积极开发中。 但是,随着它们在关键Internet属性中的采用,它们似乎都已经从有趣的开源软件过渡到了基本的Web技术。
翻译自: https://www.ibm.com/developerworks/opensource/library/os-spark/index.html
spark快速数据分析