第十章 Spark Streaming

需要应用需要即时处理收到的数据,例如训练机器学习模型的应用,自动检测异常的应用。Spark Streaming为这些应用而设计。允许用户使用一套和批处理非常接近的API来编写流式计算应用。

Spark Streaming使用离散化流(discretized stream作为抽象表示)作为抽象表示,叫做DStream。

##### DStream(不间断工作)

接收方式:随时间推移而接收到数据。

输入源:Flume、Kafka或HDFS

支持操作:转化操作 => DStream
输出操作:把数据写入外部系统

//Scala流计算import声明
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.StreamingContext._
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.Duration
import org.apache.spark.streaming.Seconds

//用Scala进行流式筛选,打印包含“error”的行
// 从SparkConf创建StreamingContext并指定1秒钟的批处理大小
val ssc = new StreamingContext(conf, Seconds(1))
// 连接到本地机器7777端口上后,使用收到的数据创建DStream
val lines = ssc.socketTextStream("localhost", 7777)
// 从DStream中筛选出包含字符串"error"的行
val errorLines = lines.filter(_.contains("error"))
// 打印出有"error"的行
errorLines.print()
// 启动流计算环境StreamingContext并等待它"完成"
ssc.start()
// 等待作业完成
ssc.awaitTermination()

一个Streaming context只能启动一次,所以只有在配置好所有DStream以及所需要的输出操作之后才能启动。

容错性

Spark Streaming 对 DStream提供的容错性与RDD一致,只要输入数据还在,就可以使用RDD谱系图重算出任意状态。 不过重算会花费很长时间。

检查点机制,可以把状态阶段存储到可靠的文件系统中(如HDFS或S3),每处理5-10批次数据就保存一次。

转化操作

1、无状态转化操作:每个批次的处理不依赖于之前批次的数据。如map(),filter(),reduceByKey()。其中各个操作都是基于时间段进行。

2、有状态转化操作:需要使用之前批次的数据或者是中间结果来计算当前批次的数据,有状态转化操作包括基于滑动窗口的转化操作和追踪状态变化的转化操作。

有状态转化操作,主要有两种类型:滑动窗口和updateStateByKey(),StateByKey主要是追踪每个键的状态变化。

有状态转化操纵需要在StreamingContext中打开检查点机制确保容错性。

//设置检查点
ssc.checkpoint("hdfs://...")
基于窗口的转化操作

时间比基于批次的间隔时间更长,整合更多的数据。

基于窗口的操作需要两个参数:1、窗口时长、2、滑动补偿。两者必须是StreamContext的批次间隔的整数倍。

reduceeByWindow()和reduceByKeyAndWindow()可以对每个窗口进行规约操作。
除了普通规约操作,还可以使用逆函数进行规约操作。移除老批次数据,引入新批次数据,极大提高执行效率。

val ipDStream = accessLogsDStream.map(logEntry => (logEntry.getIpAddress(), 1))
val ipCountDStream = ipDStream.reduceByKeyAndWindow(
{(x, y) => x + y}, // 加上新进入窗口的批次中的元素
{(x, y) => x - y}, // 移除离开窗口的老批次中的元素
Seconds(30), // 窗口时长
Seconds(10)) // 滑动步长

countByWindow()和countByValueAndWindow(),对数据进行技术操作。countBywindow()返回一个表示每个窗口中元素个数的DStream,countByValueAndWindow()返回的DStream包含窗口中每个值的个数。

//窗口计数操作
val ipDStream = accessLogsDStream.map{entry => entry.getIpAddress()}
val ipAddressRequestCount = ipDStream.countByValueAndWindow(Seconds(30), Seconds(10))
val requestCount = accessLogsDStream.countByWindow(Seconds(30), Seconds(10))

UpdateStateByKey操作

用于跨批次维护状态,updateStateByKey()为我们提供了一个状态变量的访问,用于键值对形式的DStream。

updateStateByKey(),提供了一个update(events,oldState)函数,接收与某键相关的时间以及该键之前对应的状态,返回这个键对应的新状态。

  • events:当前批次中接收到的事件的列表。
  • oldState:如果一个键没有之前的状态,这个值可以空缺
  • newState:由函数返回,也以Option形式存在;可以返回一个空的Option来表示想要删除的状态。

updateStateByKey()的结果会是一个新的DStream,其内部的RDD序列是由每个时间区间对应的(键,状态)对组成的。

//在Scala中使用updateStateByKey()运行相应代码计数
def updateRunningSum(values: Seq[Long], state: Option[Long]) = {
Some(state.getOrElse(0L) + values.size)
}
val responseCodeDStream = accessLogsDStream.map(log => (log.getResponseCode(), 1L))
val responseCodeCountDStream = responseCodeDStream.updateStateByKey(updateRunningSum _)
输出文件
//在scala中将DStream保存为文本文件
ipAddressRequestCount.saveAsTextFiles("outputDir", "txt")
//在Scala中将DStream保存为SequenceFile
val writableIpAddressRequestCount = ipAddressRequestCount.map {
(ip, count) => (new Text(ip), new LongWritable(count)) }
writableIpAddressRequestCount.saveAsHadoopFiles[
SequenceFileOutputFormat[Text, LongWritable]]("outputDir", "txt")

foreachRDD()用来对DStream中的RDD运行任意计算。在foreachRDD()中,可以重用我们在Spark中实现的所有行动操作。比如,把数据写到注入MySQL的外部数据库中,Spark没有提供对应的saveAS()函数,可以使用RDD的eachPartitioni()方法把它写进去。

//在Scala中使用foreachRDD()将数据存储到外部系统中。
ipAddressRequestCount.foreachRDD { rdd =>
rdd.foreachPartition { partition =>
// 打开到存储系统的连接(比如一个数据库的连接)
partition.foreach { item =>
// 使用连接把item存到系统中
}
// 关闭连接
}
}
输入源

1、文件流

支持从任意Hadoop兼容的文件系统中读取数据。

val logData = ssc.textFileStream(logDirectory)

读取SequenceFile流

ssc.fileStream[LongWritable, IntWritable,
SequenceFileInputFormat[LongWritable, IntWritable]](inputDirectory).map {
case (x, y) => (x.get(), y.get())
}

2、Akka actor流

另一个核心数据源接收器是actorStream,可以把AKKa actor(http://akka.io/)作为数据流的源

附加数据源

1、Apache Kaflka

在工程中需要引入maven工作spark-streaming-kafaka_2.10,包内提供的KafkaUtils对象,可以在StreamingContext和JavaStreamingContext中以Kafka消息创建出DStream,DStream由成对的主题和消息构成。

//在Scala中使用Apache Kafka定于Panda 主题
import org.apache.spark.streaming.kafka._
...
// 创建一个从主题到接收器线程数的映射表
val topics = List(("pandas", 1), ("logs", 1)).toMap
val topicLines = KafkaUtils.createStream(ssc, zkQuorum, group, topics)
StreamingLogInput.processLines(topicLines.map(_._2))

2、Apache Flume

需要引入Maven工件spark-streaming-flume_2.10
- 推式接收器

以Avro数据池的方式工作,由Flume向其中推送数据

  • 拉式接收器

从自定义的中间数据池中拉数据,而其他进程可以用Flume把数据推进中间数据池。

检查点机制

检查点机制服务目的:

1、控制发生失败时需要重算的状态数

//配置检查点
ssc.checkpoint("hdfs://...")

2、提供驱动器程序容错,驱动器崩溃,可以从检查点恢复。

//用Scala配置一个从错误中恢复的驱动程序
def createStreamingContext() = {
...
val sc = new SparkContext(conf)
// 以1秒作为批次大小创建StreamingContext
val ssc = new StreamingContext(sc, Seconds(1))
ssc.checkpoint(checkpointDir)
}
...
val ssc = StreamingContext.getOrCreate(checkpointDir, createStreamingContext _)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值