- 1. 回顾和展望
- 1.1. Spark 编程模型的进化过程
- 1.2. Spark 的 序列化 的进化过程
- 1.3. Spark Streaming 和 Structured Streaming
- 2. Structured Streaming 入门案例
- 2.1. 需求梳理
- 2.2. 代码实现
- 2.3. 运行和结果验证
- 3. Stuctured Streaming 的体系和结构
- 3.1. 无限扩展的表格
- 3.2. 体系结构
- 4. Source
- 4.1. 从 HDFS 中读取数据
- 4.2. 从 Kafka 中读取数据
- 5. Sink
- 5.1. HDFS Sink
- 5.2. Kafka Sink
- 5.3. Foreach Writer
- 5.4. 自定义 Sink
- 5.5. Tigger
- 5.6. 从 Source 到 Sink 的流程
- 5.7. 错误恢复和容错语义
- 6. 有状态算子
- 6.1. 常规算子
- 6.2. 分组算子
- 全天目标
-
-
回顾和展望
-
入门案例
-
Stuctured Streaming
的体系和结构
-
1. 回顾和展望
- 本章目标
-
Structured Streaming
是Spark Streaming
的进化版, 如果了解了Spark
的各方面的进化过程, 有助于理解Structured Streaming
的使命和作用 - 本章过程
-
-
Spark
的API
进化过程 -
Spark
的序列化进化过程 -
Spark Streaming
和Structured Streaming
-
1.1. Spark 编程模型的进化过程
- 目标
-
Spark
的进化过程中, 一个非常重要的组成部分就是编程模型的进化, 通过编程模型可以看得出来内在的问题和解决方案 - 过程
-
-
编程模型
RDD
的优点和缺陷 -
编程模型
DataFrame
的优点和缺陷 -
编程模型
Dataset
的优点和缺陷
-
编程模型 | 解释 |
---|---|
|
|
|
|
|
|
-
RDD
的优点 -
-
面向对象的操作方式
-
可以处理任何类型的数据
-
-
RDD
的缺点 -
-
运行速度比较慢, 执行过程没有优化
-
API
比较僵硬, 对结构化数据的访问和操作没有优化
-
-
DataFrame
的优点 -
-
针对结构化数据高度优化, 可以通过列名访问和转换数据
-
增加
Catalyst
优化器, 执行过程是优化的, 避免了因为开发者的原因影响效率
-
-
DataFrame
的缺点 -
-
只能操作结构化数据
-
只有无类型的
API
, 也就是只能针对列和SQL
操作数据,API
依然僵硬
-
-
Dataset
的优点 -
-
结合了
RDD
和DataFrame
的API
, 既可以操作结构化数据, 也可以操作非结构化数据 -
既有有类型的
API
也有无类型的API
, 灵活选择
-
1.2. Spark 的 序列化 的进化过程
- 目标
-
Spark
中的序列化过程决定了数据如何存储, 是性能优化一个非常重要的着眼点,Spark
的进化并不只是针对编程模型提供的API
, 在大数据处理中, 也必须要考虑性能 - 过程
-
-
序列化和反序列化是什么
-
Spark
中什么地方用到序列化和反序列化 -
RDD
的序列化和反序列化如何实现 -
Dataset
的序列化和反序列化如何实现
-
- Step 1: 什么是序列化和序列化
-
Step 2: 在
Spark
中的序列化和反序列化的应用场景 -
Step 3:
RDD
的序列化 -
Step 4:
DataFrame
和Dataset
中的序列化
-
当需要将对象缓存下来的时候, 或者在网络中传输的时候, 要把对象转成二进制, 在使用的时候再将二进制转为对象, 这个过程叫做序列化和反序列化
-
在
Spark
中有很多场景需要存储对象, 或者在网络中传输对象-
Task
分发的时候, 需要将任务序列化, 分发到不同的Executor
中执行 -
缓存
RDD
的时候, 需要保存RDD
中的数据 -
广播变量的时候, 需要将变量序列化, 在集群中广播
-
RDD
的Shuffle
过程中Map
和Reducer
之间需要交换数据 -
算子中如果引入了外部的变量, 这个外部的变量也需要被序列化
-
-
RDD
因为不保留数据的元信息, 所以必须要序列化整个对象, 常见的方式是Java
的序列化器, 和Kyro
序列化器 -
Dataset
和DataFrame
中保留数据的元信息, 所以可以不再使用Java
的序列化器和Kyro
序列化器, 使用Spark
特有的序列化协议, 生成UnsafeInternalRow
用以保存数据, 这样不仅能减少数据量, 也能减少序列化和反序列化的开销, 其速度大概能达到RDD
的序列化的20
倍左右
1.3. Spark Streaming 和 Structured Streaming
- 目标
-
理解
Spark Streaming
和Structured Streaming
之间的区别, 是非常必要的, 从这点上可以理解Structured Streaming
的过去和产生契机 - 过程
-
-
Spark Streaming
时代 -
Structured Streaming
时代 -
Spark Streaming
和Structured Streaming
-
-
Spark Streaming
时代 -
Structured Streaming
时代 -
Spark Streaming
和Structured Streaming
2. Structured Streaming 入门案例
- 目标
-
了解
Structured Streaming
的编程模型, 为理解Structured Streaming
时候是什么, 以及核心体系原理打下基础 - 步骤
-
-
需求梳理
-
Structured Streaming
代码实现 -
运行
-
验证结果
-
2.1. 需求梳理
- 目标
-
理解接下来要做的案例, 有的放矢
- 步骤
-
-
需求
-
整体结构
-
开发方式
-
- 需求
- 整体结构
- 开发方式和步骤
-
简单来说, 就是要进行流式的词频统计, 使用
Structured Streaming
2.2. 代码实现
- 目标
-
实现
Structured Streaming
部分的代码编写 - 步骤
-
-
创建文件
-
创建
SparkSession
-
读取
Socket
数据生成DataFrame
-
将
DataFrame
转为Dataset
, 使用有类型的API
处理词频统计 -
生成结果集, 并写入控制台
-
object SocketProcessor {
def main(args: Array[String]): Unit = {
// 1. 创建 SparkSession
val spark = SparkSession.builder()
.master("local[6]")
.appName("socket_processor")
.getOrCreate()
spark.sparkContext.setLogLevel("ERROR")
import spark.implicits._
// 2. 读取外部数据源, 并转为 Dataset[String]
val source = spark.readStream
.format("socket")
.option("host", "127.0.0.1")
.option("port", 9999)
.load()
.as[String]
// 3. 统计词频
val words = source.flatMap(_.split(" "))
.map((_, 1))
.groupByKey(_._1)
.count()
// 4. 输出结果
words.writeStream
.outputMode(OutputMode.Complete())
.format("console")
.start() .awaitTermination() } }
调整 Log 级别, 避免过多的 Log 影响视线 |
|
默认 readStream 会返回 DataFrame , 但是词频统计更适合使用 Dataset 的有类型 API |
|
统计全局结果, 而不是一个批次 | |
将结果输出到控制台 | |
开始运行流式应用 | |
阻塞主线程, 在子线程中不断获取数据 |
-
Structured Streaming
中的编程步骤依然是先读, 后处理, 最后落地 -
Structured Streaming
中的编程模型依然是DataFrame
和Dataset
-
Structured Streaming
中依然是有外部数据源读写框架的, 叫做readStream
和writeStream
-
Structured Streaming
和SparkSQL
几乎没有区别, 唯一的区别是,readStream
读出来的是流,writeStream
是将流输出, 而SparkSQL
中的批处理使用read
和write
2.3. 运行和结果验证
- 目标
-
代码已经编写完毕, 需要运行, 并查看结果集, 因为从结果集的样式中可以看到
Structured Streaming
的一些原理 - 步骤
-
-
开启
Socket server
-
运行程序
-
查看数据集
-
-
开启
Socket server
和运行程序 - 查看结果集
-
运行的时候需要先开启
Socket server
-
Structured Streaming
的 API 和运行也是针对结构化数据进行优化过的
3. Stuctured Streaming 的体系和结构
- 目标
-
了解
Structured Streaming
的体系结构和核心原理, 有两点好处, 一是需要了解原理才好进行性能调优, 二是了解原理后, 才能理解代码执行流程, 从而更好的记忆, 也做到知其然更知其所以然 - 步骤
-
-
WordCount
的执行原理 -
Structured Streaming
的体系结构
-
3.1. 无限扩展的表格
- 目标
-
Structured Streaming
是一个复杂的体系, 由很多组件组成, 这些组件之间也会进行交互, 如果无法站在整体视角去观察这些组件之间的关系, 也无法理解Structured Streaming
的全局 - 步骤
-
-
了解
Dataset
这个计算模型和流式计算的关系 -
如何使用
Dataset
处理流式数据? -
WordCount
案例的执行过程和原理
-
-
Dataset
和流式计算 -
如何使用
Dataset
这个编程模型表示流式计算? -
WordCount
的原理
-
Dataset
不仅可以表达流式数据的处理, 也可以表达批量数据的处理 -
Dataset
之所以可以表达流式数据的处理, 因为Dataset
可以模拟一张无限扩展的表, 外部的数据会不断的流入到其中
3.2. 体系结构
- 目标
-
Structured Streaming
是一个复杂的体系, 由很多组件组成, 这些组件之间也会进行交互, 如果无法站在整体视角去观察这些组件之间的关系, 也无法理解Structured Streaming
的核心原理 - 步骤
-
-
体系结构
-
StreamExecution
的执行顺序
-
- 体系结构
-
StreamExecution
的执行顺序 - 增量查询
-
StreamExecution
是整个Structured Streaming
的核心, 负责在流上的查询 -
StreamExecution
中三个重要的组成部分, 分别是Source
负责读取每个批量的数据,Sink
负责将结果写入外部数据源,Logical Plan
负责针对每个小批量生成执行计划 -
StreamExecution
中使用StateStore
来进行状态的维护
4. Source
- 目标和过程
4.1. 从 HDFS 中读取数据
- 目标和过程
4.1.1. 案例结构
- 目标和步骤
- 案例流程
- 实现步骤
- 难点和易错点
- 总结
4.1.2. 产生小文件并推送到 HDFS
- 目标和步骤
- 代码编写
- 总结
4.1.3. 流式计算统计 HDFS 上的小文件
- 目标和步骤
- 代码
- 总结
4.1.4. 运行和流程总结
- 目标和步骤
- 运行 Python 程序
- 运行 Spark 程序
- 总结
4.2. 从 Kafka 中读取数据
- 目标和步骤
4.2.1 Kafka 的场景和结构
- 目标和步骤
- Kafka 是一个 Pub / Sub 系统
- Kafka 的特点
- Topic 和 Partitions
- 总结
4.2.2. Kafka 和 Structured Streaming 整合的结构
- 目标和步骤
- Topic 的 Offset
- Kafka 和 Structured Streaming 整合的结构
- Structured Streaming 读取 Kafka 消息的三种方式
- 总结
4.2.3. 需求介绍
- 目标和步骤
- 需求
- 数据转换
- 总结
4.2.4. 使用 Spark 流计算连接 Kafka 数据源
- 目标和步骤
- 创建 Topic 并输入数据到 Topic
- 使用 Spark 读取 Kafka 的 Topic
- 总结
4.2.5. JSON 解析和数据统计
- 目标和步骤
- JSON 解析
- 数据处理
- 全部代码
- 运行测试
5. Sink
- 目标和步骤
5.1. HDFS Sink
- 目标和步骤
- 场景和需求
- 代码实现
5.2. Kafka Sink
- 目标和步骤
- 场景
- 代码
5.3. Foreach Writer
- 目标和步骤
- 需求
- 代码
5.4. 自定义 Sink
- 目标和步骤
- Spark 加载 Sink 流程分析
- 自定义 Sink
5.5. Tigger
- 目标和步骤
- 微批次处理
- 连续流处理
5.6. 从 Source 到 Sink 的流程
- 目标和步骤
- 从 Source 到 Sink 的流程
5.7. 错误恢复和容错语义
- 目标和步骤
- 端到端
- 三种容错语义
- Sink 的容错
- 容错所需要的存储
- 需要的外部支持
6. 有状态算子
- 目标和步骤
- 状态
- 总结
6.1. 常规算子
- 目标和步骤
- 案例
- 总结
6.2. 分组算子
- 目标和步骤
- 案例
- 总结
-
-
Structured Streaming
不仅支持groupBy
, 还支持groupByKey
-