一 Spark工作模式
Spark引擎提供了在集群中所有主机上进行分布式内存数据处理的能力,下图显示了一个典型Spark job的处理流程。
![](https://i-blog.csdnimg.cn/blog_migrate/e964fdf31691c50dd421cddd481f0723.jpeg)
下图显示了Apache Spark如何在集群中执行一个作业。
![](https://i-blog.csdnimg.cn/blog_migrate/27cad10f73fe22a46685a4fc31d4dcb4.jpeg)
Master控制数据如何被分割,利用了数据本地性,并在Slaves上跟踪所有分布式计算。在某个Slave不可用时,其存储的数据会分配给其他可用的Slaves。虽然当下(1.0.1版本)Master还存在单点故障,但后期必然会被修复。
二、弹性分布式数据集(Resilient Distributed Dataset,RDD)
弹性分布式数据集(RDD,从Spark 1.3版本开始已被DataFrame替代)是Apache Spark的核心理念。它是由数据组成的不可变分布式集合,其主要进行两个操作:transformation和action。Transformation是类似在RDD上做 filter()、map()或union() 以生成另一个RDD的操作,而action则是count()、first()、take(n)、collect() 等促发一个计算并返回值到Master或者稳定存储系统的操作。Transformations一般都是lazy的,直到action执行后才会被执行。Spark Master/Driver会保存RDD上的Transformations。这样一来,如果某个RDD丢失(也就是salves宕掉),它可以快速和便捷地转换到集群中存活的主机上。这也就是RDD的弹性所在。
下图展示了Transformation的lazy:
![](https://i-blog.csdnimg.cn/blog_migrate/5c94bc358b551e3a4012178693b2b944.jpeg)
我们可以通过下面示例来理解这个概念:从文本中发现5个最常用的word。下图显示了一个可能的解决方案。
三、Spark SQL
通过Spark Engine,Spark SQL提供了一个便捷的途径来进行交互式分析,使用一个被称为SchemaRDD类型的RDD。SchemaRDD可以通过已有RDDs建立,或者其他外部数据格式,比如Parquet files、JSON数据,或者在Hive上运行HQL。SchemaRDD非常类似于RDBMS中的表格。一旦数据被导入SchemaRDD,Spark引擎就可以对它进行批或流处理。Spark SQL提供了两种类型的Contexts——SQLContext和HiveContext,扩展了SparkContext的功能。
SparkContext提供了到简单SQL parser的访问,而HiveContext则提供了到HiveQL parser的访问。HiveContext允许企业利用已有的Hive基础设施。
这里看一个简单的SQLContext示例。
下面文本中的用户数据通过“|”来分割。
[Plain Text]
01 | John Smith|38|M|201 East Heading Way #2203,Irving, TX,75063 Liana Dole|22|F|1023 West Feeder Rd, Plano,TX,75093 Craig Wolf|34|M|75942 Border Trail,Fort Worth,TX,75108 John Ledger|28|M|203 Galaxy Way,Paris, TX,75461 Joe Graham|40|M|5023 Silicon Rd,London,TX,76854 |
定义Scala case class来表示每一行:
[Plain Text]
01 | case class Customer(name:String,age:Int,gender:String,address: String) |
下面的代码片段体现了如何使用SparkContext来建立SQLContext,读取输入文件,将每一行都转换成SparkContext中的一条记录,并通过简单的SQL语句来查询30岁以下的男性用户。
[Scala]
01 | val sparkConf = new SparkConf().setAppName(“Customers”) |
02 | val sc = new SparkContext(sparkConf) |
03 | val sqlContext = new SQLContext(sc) |
04 | val r = sc.textFile(“/Users/akuntamukkala/temp/customers.txt”) val records = r.map( _ .split(‘|’)) |
05 | val c = records.map(r = >Customer(r( 0 ),r( 1 ).trim.toInt,r( 2 ),r( 3 ))) c.registerAsTable(“customers”) |
[Scala]
01 | sqlContext.sql(“select * from customers where gender = ’M’ and age < |
02 | 30 ”).collect().foreach(println) Result : [John Ledger, 28 ,M, 203 Galaxy Way,Paris, |
03 | TX, 75461 ] |
更多使用SQL和HiveQL的示例请访问下面链接 https://spark.apache.org/docs/latest/sql-programming-guide.html、 https://databricks-training.s3.amazonaws.com/data-exploration-using-spark-sql.html。
![](https://i-blog.csdnimg.cn/blog_migrate/ef707797ebf9bcc8fa75900ea30018c3.jpeg)
九、Spark Streaming
Spark Streaming提供了一个可扩展、容错、高效的途径来处理流数据,同时还利用了Spark的简易编程模型。从真正意义上讲,Spark Streaming会将流数据转换成micro batches,从而将Spark批处理编程模型应用到流用例中。这种统一的编程模型让Spark可以很好地整合批量处理和交互式流分析。下图显示了Spark Streaming可以从不同数据源中读取数据进行分析。
![](https://i-blog.csdnimg.cn/blog_migrate/5c05f7d15cb5c0634a5575c4c8d834cc.jpeg)
Spark Streaming中的核心抽象是Discretized Stream(DStream)。DStream由一组RDD组成,每个RDD都包含了规定时间(可配置)流入的数据。图12很好地展示了Spark Streaming如何通过将流入数据转换成一系列的RDDs,再转换成DStream。每个RDD都包含两秒(设定的区间长度)的数据。在Spark Streaming中,最小长度可以设置为0.5秒,因此处理延时可以达到1秒以下。
Spark Streaming同样提供了 window operators,它有助于更有效率在一组RDD( a rolling window of time)上进行计算。同时,DStream还提供了一个API,其操作符(transformations和output operators)可以帮助用户直接操作RDD。下面不妨看向包含在Spark Streaming下载中的一个简单示例。示例是在Twitter流中找出趋势hashtags,详见下面代码。
spark-1.0.1/examples/src/main/scala/org/apache/spark/examples/streaming/TwitterPopularTags.scala
[Scala]
01 | val sparkConf = new SparkConf().setAppName(“TwitterPopularTags”) |
02 | val ssc = new StreamingContext(sparkConf, Seconds( 2 )) |
03 | val stream = TwitterUtils.createStream(ssc, None, filters) |
上述代码用于建立Spark Streaming Context。Spark Streaming将在DStream中建立一个RDD,包含了每2秒流入的tweets。
[Scala]
01 | val hashTags = stream.flatMap(status = > status.getText.split(“ “).filter( _ .startsWith(“ # ”))) |
上述代码片段将Tweet转换成一组words,并过滤出所有以a#开头的。
val topCounts60 = hashTags.map((_, 1)).reduceByKeyAndWindow(_ + _, Seconds(60)).map{case (topic, count) => (count, topic)}. transform(_.sortByKey(false))
上述代码展示了如何整合计算60秒内一个hashtag流入的总次数。
[Scala]
01 | topCounts 60 .foreachRDD(rdd = > { |
02 | val topList = rdd.take( 10 ) |
03 | println(“\nPopular topics in last 60 seconds ( % s |
04 | total) : ”.format(rdd.count())) topList.foreach{ case (count, tag) = > println(“ % s ( % s |
05 | tweets)”.format(tag, count))} }) |
上面代码将找出top 10趋势tweets,然后将其打印。
[Plain Text]
01 | ssc.start() |
上述代码让Spark Streaming Context 开始检索tweets。一起聚焦一些常用操作,假设我们正在从一个socket中读入流文本。
[Scala]
01 | al lines = ssc.socketTextStream(“localhost”, 9999 , StorageLevel.MEMORY _ AND _ DISK _ SER) |
![](https://i-blog.csdnimg.cn/blog_migrate/155865d64feafe78eadf4f4ff9c5430c.jpeg)