1.流计算与批处理的区别
1.对于数据来说,流计算的数据是源源不断的,批处理的数据是固定的
2.对于计算来说,流计算的数据是增量的吗,批计算是全量的
2.sparkstreaming原理
1.DStream的有向无环图
有向无环图就是数据的处理过程
spark streaming的编程模型是DStream, 所有API都从它开始, 它是一个管道,数据渊源不断地从这个管道进去,被处理,再出去.数据处理是对数据按照时间切分为一个个小的RDD,然后针对RDD进行处理.
2.Receiver用来接收数据,保证并行的读取外部数据源
很多外部的队列和存储系统是分块的,RDD是分区的,在读取外部数据源的时候,会用不同的分区对照外部系统的分片,比如RDD对应Kafka的分区,这个receiver机制保证并行读取数据源
receiver的执行过程:
1.sparkstreaming程序启动的时候,Receiver Tracker使用JobScheduler分发Job到不同节点,每个节点包含一个Task,这个Task就是Receiver Supervisor
2.ReceiverSupervisor启动后运行Receiver实例
3.Receiver启动后,持续不断的接收外界数据,并持续的交给ReceiverSupervisor进行存储
4.Receiver Supervisor通过Block Manager进行存储数据
5.获取数据存储完成后发送元数据给Driver端的Receiver Tracker
3.容错
1、热备:通过存储级别进行备份 Storage Level.MEMORY_AND_DISK_SER
2、冷备:通过WAL预写日志进行备份
3、重放:必须要求外部数据源支持重放。比如kafka可以根据offset来获取数据
4.sparkstreaming算子:
1、updateStateByKey((当前批次中key对应的所有的value值:Seq[V],之前所有批次的key的统计结果:Option[V])=>Option[V])
1、作用: 统计全局结果
2.updateStateByKey将中间状态存入CheckPoint(必须设置)中,使用中间状态来记录中间结果,从而每次来一批数据,计算后和中间状态求和,就完成了总数的统计
2、窗口函数:
1、window
2、简写形式:reduceByKeyAndWindow(数据处理函数,窗口长度,滑动长度)
窗口长度:是指要处理数据的时间长度
滑动长度:是指距离下一次数据处理的时间间隔
滑动长度小于窗口长度会导致数据重复处理
滑动长度大于窗口长度会导致数据丢失
窗口长度与滑动长度必须是批次时间的整数倍
5.Structured Streaming与spark steaming的区别与原理
spark Streaming是RDD的API的流式工具,本质还是RDD,小批次
Structured Streaming是Dataset的API流式工具,API和Datset保持高度一致,实时流
原理:
在 Structured Streaming 中负责整体流程和执行的驱动引擎叫StreamExecution,它基于Dataset无限的表进行查询,StreamExecution中三个重要的组成部分, 分别是 Source 负责读取每个批量的数据, Sink 负责将结果写入外部数据源, Logical Plan 负责针对每个小批量生成执行计划
增量查询的步骤:
1.从StateStore中取出上次执行完成后的状态(它是全局范围)
2.把上次执行的结果加入本批次,在进行计算,得出全局结果
3.将当前批次的结果放入state store中,留待下次使用
6.整合Kafka演示代码
package structuredStreaming
import java.sql.{Connection, DriverManager, PreparedStatement}
import com.alibaba.fastjson.{JSON, JSONObject}
import org.apache.spark.sql.streaming.OutputMode
import org.apache.spark.sql.{ForeachWriter, Row, SparkSession}
object KafkaSink {
def main(args: Array[String]): Unit = {
//1、创建SparkSession
val spark = SparkSession.builder().master("local[4]").appName("kafka").getOrCreate()
spark.sparkContext.setLogLevel("warn")
//2、从kafka读取数据
val source = spark.readStream
.format("kafka")
.option("kafka.bootstrap.servers", "hadoop01:9092,hadoop03:9092,hadoop02:9092")
.option("subscribe", "spark_10")
.option("startingOffsets", "earliest")
.load()
//3、数据处理
import spark.implicits._
val result = source.selectExpr("CAST(value as string) as value").as[String]
.map(json=>{
val jsonObject = JSON.parseObject(json)
val lastEvent = jsonObject.getJSONObject("devices")
.getJSONObject("cameras")
.getJSONObject("last_event")
val hasPerson = lastEvent.getString("has_person")
val startTime = lastEvent.getString("start_time")
val obj = Obj(startTime,hasPerson)
JSON.toJSONString(obj)
})
//4、结果展示
result.writeStream.outputMode(OutputMode.Append())
.format("kafka")
.option("checkpointLocation","checkpoint")
.option("kafka.bootstrap.servers","hadoop01:9092,hadoop03:9092,hadoop02:9092")
.option("topic","spark_10_1")
.start()
.awaitTermination()
}
}
case class Obj(startTime:String,hasPerson:String)