Spark Stream 教程

原创 2016年08月29日 12:51:27
import org.apache.spark.SparkConf
import org.apache.spark.storage.StorageLevel
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.log4j.{Level, Logger}
import java.util.concurrent

object NetworkWordCount {
  def main(args: Array[String]) {
    if (args.length < 2) {
      System.err.println("Usage: NetworkWordCount ")
      System.exit(1)
    }

    //StreamingExamples.setStreamingLogLevels()
    // 屏蔽不必要的日志显示终端上
    Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
    
    // Create the context with a 1 second batch size  1秒为单位分割数据流
    val sparkConf = new SparkConf().setAppName("NetworkWordCount")
    val ssc = new StreamingContext(sparkConf, Seconds(1))

    // Create a socket stream on target ip:port and count the
    // words in input stream of \n delimited text (eg. generated by 'nc')
    // Note that no duplication in storage level only for running locally.
    // Replication necessary in distributed scenario for fault tolerance.
    val lines = ssc.socketTextStream(args(0), args(1).toInt, StorageLevel.MEMORY_AND_DISK_SER)
    val words = lines.flatMap(_.split(" "))
    val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)
    wordCounts.print()
    ssc.start()
    ssc.awaitTermination()
  }
}
// scalastyle:on println


编译好jar之后,编辑./testStream.sh
/opt/cloudera/parcels/CDH-5.6.0-1.cdh5.6.0.p0.45/lib/spark/bin/spark-submit \
--class NetworkWordCount \
--master local[2] \
SparkStream.jar \
localhost 9999
~                                                          


localhost 9999表示它表示从TCP源(主机位localhost,端口为9999)获取的流式数据。
这个lines变量是一个DStream,表示即将从数据服务器获得的流数据。这个DStream的每条记录都代表一行文本。下一步,我们需要将DStream中的每行文本都切分为单词。
  1. 另外在本机新开一个命令行窗口,做4-7的操作
  2. nc -lk 9999,守候9999端口(改命令是监听,sudo yum install NetCat,一般安装时都没有装
  3. 在第一个窗口./testStream.sh
  4. 切换到nc -lk 9999窗口,屏幕显示进入等待输入
  5. 此时输入hello world ,然后回车
  6. 回到第一个命令行窗口,可见屏幕上有已经key-value分解了的
hello 1
world 1

字样,表明已经被stream按单词出现的数量处理好了

还可以
cat file1.txt | nc -lk 9999
上条命令中的红色竖杠就是管道
 在这些转换操作准备好之后,要真正执行计算,需要调用如下的方法

ssc.start()             // Start the computation
ssc.awaitTermination()  // Wait for the computation to terminate

或者ssc.awaitTermination(30000)  // 等待结束或者超过30自动结束

再或者

   ssc.start()
   Thread.sleep(30000)
   ssc.stop() 

大概执行30s后自动结束

离散流或者DStreams是Spark Streaming提供的基本的抽象,它代表一个连续的数据流。比如我们这里的1s一个DStream

Spark <wbr>Stream <wbr>教程



Spark Streaming拥有两类数据源
  • 基本源(Basic sources):这些源在StreamingContext API中直接可用。例如文件系统、套接字连接、Akka的actor等。
  • streamingContext.fileStream[keyClass, valueClass, inputFormatClass](dataDirectory)

    Spark Streaming将会监控dataDirectory目录,并且处理目录下生成的任何文件(嵌套目录不被支持)。需要注意:

    
    1 所有文件必须具有相同的数据格式
    2 所有文件必须在`dataDirectory`目录下创建
    
  • 
    对于简单的文本文件,有一个更简单的方法streamingContext.textFileStream(dataDirectory)可以被调用。
    
  • 
    
    • 基于自定义actor的流:DStream可以调用streamingContext.actorStream(actorProps, actor-name)方法从Akka actors获取的数据流来创建。具体的信息见自定义receiver指南 actorStream在Python API中不可用。
    • RDD队列作为数据流:为了用测试数据测试Spark Streaming应用程序,人们也可以调用streamingContext.queueStream(queueOfRDDs)方法基于RDD队列创建DStreams。每个push到队列的RDD都被 当做DStream的批数据,像流一样处理。
  • 高级源(Advanced sources):这些源包括Kafka,Flume,Kinesis,Twitter等等。它们需要通过额外的类来使用。 为了从Kafka, Flume和Kinesis这些不在Spark核心API中提供的源获取数据,我们需要添加相关的模块spark-streaming-xyz_2.10到依赖中。例如,一些通用的组件如下表所示:
  • Source Artifact
    Kafka spark-streaming-kafka_2.10
    Flume spark-streaming-flume_2.10
    Kinesis spark-streaming-kinesis-asl_2.10
    Twitter spark-streaming-twitter_2.10
    ZeroMQ spark-streaming-zeromq_2.10
    MQTT spark-streaming-mqtt_2.10

    为了获取最新的列表,请访问Apache repository

参考http://www.cnblogs.com/shishanyuan/p/4747749.html
对于SocketWordCount(跟NetworkWordCount差不多,就是每10s一个Dtream这里就不给了
先执行Socket模拟器(模拟器Socket端口号为9999,频度为1秒,
/opt/cloudera/parcels/CDH-5.6.0-1.cdh5.6.0.p0.45/lib/spark/bin/spark-submit \
--class StreamingSimulation \
--master local[2] \
SparkStream.jar \
people.txt 9999 1000

people.txt 为当前目录下的一个文件,每行1个单词,

在执行SocketWordCount
/opt/cloudera/parcels/CDH-5.6.0-1.cdh5.6.0.p0.45/lib/spark/bin/spark-submit \
--class SocketWordCount \
--master local[2] \
SparkStream.jar \
localhost 9999
可以看到效果
Spark <wbr>Stream <wbr>教程

可以发现,由于10s一个Dtream,所以正好从socket接受10个单词。

UpdateStateByKey操作

updateStateByKey操作允许不断用新信息更新它的同时保持任意状态。你需要通过两步来使用它

  • 定义状态-状态可以是任何的数据类型
  • 定义状态更新函数-怎样利用更新前的状态和从输入流里面获取的新值更新状态

让我们举个例子说明。在上面的例子中,每次显示10个单词,下一次显示另外10个,之间没有关联。如果你想保持一个文本数据流中每个单词的运行次数,运行次数用一个state表示,它的类型是整数


def updateFunction(newValues: Seq[Int], runningCount: Option[Int]): Option[Int] = {
    val newCount = ...  // add the new values with the previous running count to get the new count
    Some(newCount)
}

这个函数被用到了DStream包含的单词上

// 定义更新状态方法,参数values为当前批次单词频度,state为以往批次单词频度

    val updateFunc = (values: Seq[Int], state: Option[Int]) => {

      val currentCount = values.foldLeft(0)(_ + _)

      val previousCount = state.getOrElse(0)

      Some(currentCount + previousCount)

    }

更新函数将会被每个单词调用,wordCounts拥有一系列的1(从  val wordCounts = words.map(x => (x, 1))对而来),stateDstream拥有之前的次数。  

val stateDstream = wordCounts.updateStateByKey[Int](updateFunc)


import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.StreamingContext._
 
object StatefulWordCount {
  def main(args: Array[String]) {
    if (args.length != 2) {
      System.err.println("Usage: StatefulWordCount ")
      System.exit(1)
    }
    Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
 
    // 定义更新状态方法,参数values为当前批次单词频度,state为以往批次单词频度
    val updateFunc = (values: Seq[Int], state: Option[Int]) => {
      val currentCount = values.foldLeft(0)(_ + _)
      val previousCount = state.getOrElse(0)
      Some(currentCount + previousCount)
    }
 
    val conf = new SparkConf().setAppName("StatefulWordCount").setMaster("local[2]")
    val sc = new SparkContext(conf)
 
    // 创建StreamingContext,Spark Steaming运行时间间隔为5秒
    val ssc = new StreamingContext(sc, Seconds(5))
    // 定义checkpoint目录为当前目录
    ssc.checkpoint(".")
 
    // 获取从Socket发送过来数据
    val lines = ssc.socketTextStream(args(0), args(1).toInt)
    val words = lines.flatMap(_.split(","))
    val wordCounts = words.map(x => (x, 1))
 
    // 使用updateStateByKey来更新状态,统计从运行开始以来单词总的次数
    val stateDstream = wordCounts.updateStateByKey[Int](updateFunc)
    stateDstream.print()
    ssc.start()
    ssc.awaitTermination()
  }
}

这样,这个例子相比较前面实例中各时间段之间状态是相关的。
Spark <wbr>Stream <wbr>教程


上面程序中还要注意:

Checkpointing

一个流应用程序必须全天候运行,所有必须能够解决应用程序逻辑无关的故障(如系统错误,JVM崩溃等)。为了使这成为可能,Spark Streaming需要checkpoint足够的信息到容错存储系统中, 以使系统从故障中恢复。

何时checkpoint

应用程序在下面两种情况下必须开启checkpoint

  • 使用有状态的transformation。如果在应用程序中用到了updateStateByKey或者reduceByKeyAndWindow,checkpoint目录必需提供用以定期checkpoint RDD。
  • 从运行应用程序的driver的故障中恢复过来。使用元数据checkpoint恢复处理信息。

注意,没有前述的有状态的transformation的简单流应用程序在运行时可以不开启checkpoint。在这种情况下,从driver故障的恢复将是部分恢复(接收到了但是还没有处理的数据将会丢失)。 这通常是可以接受的,许多运行的Spark Streaming应用程序都是这种方式。

刚刚程序里面 // 定义checkpoint目录为当前目录

    ssc.checkpoint(".")
所以在hadoop的HDFS的当前目录下就会有记录
Spark <wbr>Stream <wbr>教程
当然,打开都是乱码,劝你不用打开看看是啥了。

至于怎么使用checkpoint来从故障中恢复,可以参考
https://github.com/apache/spark/blob/master/examples/src/main/scala/org/apache/spark/examples/streaming/RecoverableNetworkWordCount.scala
https://aiyanbo.gitbooks.io/spark-programming-guide-zh-cn/content/spark-streaming/basic-concepts/checkpointing.html

窗口(window)操作

Spark Streaming也支持窗口计算,它允许你在一个滑动窗口数据上应用transformation算子。下图阐明了这个滑动窗口。

任何一个窗口操作都需要指定两个参数:

  • 窗口长度:窗口的持续时间
  • 滑动的时间间隔:窗口操作执行的时间间隔

这两个参数必须是源DStream的批时间间隔的倍数。

下面举例说明窗口操作。例如,你想扩展前面的例子用来计算过去30秒的词频,间隔时间是20秒。为了达到这个目的,我们必须在过去30秒的pairs DStream上应用reduceByKey 操作。用方法reduceByKeyAndWindow实现。

+

// Reduce last 30 seconds of data, every 10 seconds
val windowedWordCounts = pairs.reduceByKeyAndWindow((a:Int,b:Int) => (a + b), Seconds(30), Seconds(20))
对应的图如下:
Spark <wbr>Stream <wbr>教程


val ssc = new StreamingContext(sc, Seconds(5))
     // 定义checkpoint目录为当前目录
    ssc.checkpoint(".")
 
    // 通过Socket获取数据,该处需要提供Socket的主机名和端口号,数据保存在内存和硬盘中
    val lines = ssc.socketTextStream(args(0), args(1).toInt, StorageLevel.MEMORY_ONLY_SER)
    val words = lines.flatMap(_.split(","))
 
    // windows操作,第一种方式为叠加处理,第二种方式为增量处理
    val wordCounts = words.map(x => (x , 1)).reduceByKeyAndWindow((a:Int,b:Int) => (a + b), Seconds(args(2).toInt), Seconds(args(3).toInt))
//val wordCounts = words.map(x => (x , 1)).reduceByKeyAndWindow(_+_, _-_,Seconds(args(2).toInt), Seconds(args(3).toInt))
 
    wordCounts.print()
    ssc.start()
    ssc.awaitTermination()

这里源DStream的批时间间隔是5,两个参数都要是5的倍数。

Spark <wbr>Stream <wbr>教程
从结果可以看出,第一次算了5个,第二次算了15个,第3次算了25个,第四次算了30个,第5次算了30个。。。后面每次都算一个窗口的大小30个。(前面不是30个是因为窗口还没填满)

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

wind7&nbsp;安装IIS教程

一、进入Windows7的控制面板,选择左侧的打开或关闭Windows功能。 二、现在出现了安装Windows功能的选项菜单,注意选择的项目,我们需要手动选择需要的功能,下面这张图片把需要安...

HTML中&nbsp; &ensp; &emsp; &thinsp;等6种空白空格的区别

HTML中&nbsp; &ensp; &emsp; &thinsp;等6种空白空格的区别 HTML提供了5种空格实体(space entity),它们拥有不同的宽度,非断行空格(&nbsp;...

iOS 2.3.7 Your app name to be displayed on the&nbsp

复制原文只为自己查找方便(  原文 ) 苹果审核条款 惊!苹果再次加强审核力度,众App纷纷止步应用标题 近日,在和开发者交流的过程中,我们得到了以下反馈:App ...

android端ios端&nbsp;视频、文件高效加密

近期做项目遇到加密问题,通过在网上查阅大量资料,看见不少人提出通过给文件头部和尾部添加数据等方法,自己测试了一下,一个50m的文件通过这种方法,加解密时需要5s以上(用到了复制文件操作),这肯定不适合...

AM335X&nbsp uboot烧写

原创:http://blog.sina.com.cn/u/2312748742 NAND地址如下:  +------------+-->0x00000000-> SPL start ...

html空件不可见&nbsp;文字滚动

id="playerinfo" style="display:none">1     html空件不可见         [HTML代码]会移动的文字(Marq...

关于&nbsp;空格实体在最新的IE、Firefox和Google Chrome浏览器中解析宽度不一致问题的解决

如文章标题,网络上大多数人说是页面编码和字体设置的问题,可是我照着做了,发现在  Google Chrome浏览器中&nbsp;解析成的空格宽度仍然比IE和Firefox上的宽,IE和Fire...
  • twtja
  • twtja
  • 2015-07-08 15:52
  • 1843

org.springframework.beans.factory.BeanCreationException: Error creating bean&nbsp

异常: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'admin...

&nbsp|&quot|&amp|&lt|&gt等html字符转义

提示:请直接按CTRL+F搜索您要查找的转义字符。 常用表: No. 文字表記 10進表記 16進表記 文字   ...

JSP&nbsp;EL表达式详细介绍

原文来处 一、JSP EL语言定义 E L(Expression Language)目的:为了使JSP写起来更加简单。 表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)