spark streaming支持的业务场景:
1、无状态操作:
每个批次处理都不依赖于先前批次的数据,只关注当前的DStream中的实时数据,例如 只对当前的DStream中的数据做正确性校验。
每个DStream在内部是由许多个RDD(也叫批次)组成,且无状态转化操作是分别应用到每个RDD上的。
无状态转化操作的例子map、filter等等,操作都是每个批次中的数据,但是DStream如果使用join,union等基于健的操作的话,那么所传的RDD就必须同样也是DStream才行。
SparkStreaming中无状态操作的算子:
Map
filter
flatMap
repartition
reduceByKey
groupByKey
2、有状态操作:
依赖之前的批次数据或者中间结果来计算当前批次的数据
状态管理函数:
- updateStateByKey
- mapWithState
Spark Streaming中状态管理函数包括updateStateByKey和mapWithState,都是用来统计全局key的状态的变化的。它们以DStream中的数据进行按key做reduce操作,然后对各个批次的数据进行累加,在有新的数据信息进入或更新时。能够让用户保持想要的不论任何状状。
1)UpdateStateByKey
概念:
会统计全局的key的状态,不管有没有数据输入,它会在每一个批次间隔返回之前的key的状态。会对已存在的key进行state的状态更新,同时还会对每个新出现的key执行相同的更新函数操作。如果通过更新函数对state更新后返回回来为none,此时key对应的state状态会被删除(state可以是任意类型的数据的结构).
updateStateByKey()的结果会是一个新的DStream,其内部的RDD序列是由每个时间区间对应的(键,状态)对组成的。updateStateByKey操作使得我们可以在用新信息进行更新时保持任意的状态。
条件:
定义状态,状态可以是一个任意的数据类型。
定义状态更新函数,用此函数阐明如何使用之前的状态和来自输入流的新值对状态进行更新。
使用updateStateByKey需要对检查点目录进行配置,会使用检查点来保存状态
适用场景:
updateStateByKey可以用来统计历史数据,每次输出所有的key值。例如统计不同时间段用户平均消费金额,消费次数,消费总额,网站的不同时间段的访问量等指标.
代码:
package com.atguigu.bigdata.spark.streaming
import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}
// 有状态数据统计
object SparkStreaming_UpdateState {
def main(args: Array[String]): Unit = {
// 使用SparkStreaming完成WordCount
// Spark配置对象
val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkStreaming01_WordCount")
// 实时数据分析环境对象
// 采集周期:以指定的时间为周期采集实时数据
val streamingContext = new StreamingContext(sparkConf, Seconds(5))
// 保存数据的状态,需要设定检查点路径
streamingContext.sparkContext.setCheckpointDir("cp")
// 从Kafka中采集数据
//streamingContext.receiverStream(new MyReceiver("linux1", 9999))
val kafkaDStream: ReceiverInputDStream[(String, String)] = KafkaUtils.createStream(
streamingContext,
"linux1:2181",
"atguigu",
Map("atguigu" -> 3)
)
// 将采集的数据进行分解(扁平化)
val wordDStream: DStream[String] = kafkaDStream.flatMap(t=>t._2.split(" "))
// 将数据进行结构的转换方便统计分析
val mapDStream: DStream[(String, Int)] = wordDStream.map((_, 1))
// 将转换结构后的数据进行聚合处理
val wordToSumDStream: DStream[(String, Int)] = mapDStream.reduceByKey(_+_)
/*
val stateDStream: DStream[(String, Int)] = mapDStream.updateStateByKey {
case (seq, buffer) => {
val sum = buffer.getOrElse(0) + seq.sum
Option(sum)
}
}
*/
//value
// 将结果打印出来
wordToSumDStream.print()
// 不能停止采集程序</