Spark(五)--Structured Streaming(三) - 体系和结构

3. Stuctured Streaming 的体系和结构

目标
了解 Structured Streaming 的体系结构和核心原理, 有两点好处, 一是需要了解原理才好进行性能调优, 二是了解原理后, 才能理解代码执行流程, 从而更好的记忆, 也做到知其然更知其所以然

步骤
WordCount 的执行原理
Structured Streaming 的体系结构

3.1 无限扩展的表格

目标
Structured Streaming 是一个复杂的体系, 由很多组件组成, 这些组件之间也会进行交互, 如果无法站在整体视角去观察这些组件之间的关系, 也无法理解 Structured Streaming 的全局

步骤
    了解 Dataset 这个计算模型和流式计算的关系
    如何使用 Dataset 处理流式数据?
    WordCount 案例的执行过程和原理

3.1.1 Dataset 和流式计算

可以理解为 Spark 中的 Dataset 有两种, 一种是处理静态批量数据的 Dataset, 一种是处理动态实时流的 Dataset, 这两种 Dataset 之间的区别如下

  • 流式的 Dataset 使用 readStream 读取外部数据源创建, 使用 writeStream 写入外部存储

  • 批式的 Dataset 使用 read 读取外部数据源创建, 使用 write 写入外部存储

3.1.2 如何使用 Dataset 这个编程模型表示流式计算?

  • 可以把流式的数据想象成一个不断增长, 无限无界的表

  • 无论是否有界, 全都使用 Dataset 这一套 API

  • 通过这样的做法, 就能完全保证流和批的处理使用完全相同的代码, 减少这两种处理方式的差异

3.1.3 WordCount 的原理

  • 整个计算过程大致上分为如下三个部分

    1. Source, 读取数据源

    2. Query, 在流式数据上的查询

    3. Result, 结果集生成

  • 整个的过程如下

    1. 随着时间段的流动, 对外部数据进行批次的划分

    2. 在逻辑上, 将缓存所有的数据, 生成一张无限扩展的表, 在这张表上进行查询

    3. 根据要生成的结果类型, 来选择是否生成基于整个数据集的结果

3.1.4 总结

  • Dataset 不仅可以表达流式数据的处理, 也可以表达批量数据的处理

  • Dataset 之所以可以表达流式数据的处理, 因为 Dataset 可以模拟一张无限扩展的表, 外部的数据会不断的流入到其中

3.2 体系结构

目标

Structured Streaming 是一个复杂的体系, 由很多组件组成, 这些组件之间也会进行交互, 如果无法站在整体视角去观察这些组件之间的关系, 也无法理解 Structured Streaming 的核心原理

步骤

  1. 体系结构

  2. StreamExecution 的执行顺序

3.2.1 体系结构

在 Structured Streaming 中负责整体流程和执行的驱动引擎叫做 StreamExecution

StreamExecution 在流上进行基于 Dataset 的查询, 也就是说, Dataset 之所以能够在流上进行查询, 是因为 StreamExecution 的调度和管理

StreamExecution 如何工作?

StreamExecution 分为三个重要的部分

  • Source, 从外部数据源读取数据

  • LogicalPlan, 逻辑计划, 在流上的查询计划

  • Sink, 对接外部系统, 写入结果

3.2.2 StreamExecution 的执行顺序

根据进度标记, 从 Source 获取到一个由 DataFrame 表示的批次, 这个 DataFrame 表示数据的源头

val source = spark.readStream
  .format("socket")
  .option("host", "127.0.0.1")
  .option("port", 9999)
  .load()
  .as[String]

这一点非常类似 val df = spark.read.csv() 所生成的 DataFrame, 同样都是表示源头

根据源头 DataFrame 生成逻辑计划

val words = source.flatMap(_.split(" "))
  .map((_, 1))
  .groupByKey(_._1)
  .count()

上述代码表示的就是数据的查询, 这一个步骤将这样的查询步骤生成为逻辑执行计划

优化逻辑计划最终生成物理计划

这一步其实就是使用 Catalyst 对执行计划进行优化, 经历基于规则的优化和基于成本模型的优化

执行物理计划将表示执行结果的 DataFrame / Dataset 交给 Sink

整个物理执行计划会针对每一个批次的数据进行处理, 处理后每一个批次都会生成一个表示结果的 Dataset

Sink 可以将每一个批次的结果 Dataset 落地到外部数据源

执行完毕后, 汇报 Source 这个批次已经处理结束, Source 提交并记录最新的进度

3.2.3 增量查询

核心问题

上图中清晰的展示了最终的结果生成是全局的结果, 而不是一个批次的结果, 但是从 StreamExecution 中可以看到, 针对流的处理是按照一个批次一个批次来处理的

那么, 最终是如何生成全局的结果集呢?

状态记录

在 Structured Streaming 中有一个全局范围的高可用 StateStore, 这个时候针对增量的查询变为如下步骤

  1. 从 StateStore 中取出上次执行完成后的状态

  2. 把上次执行的结果加入本批次, 再进行计算, 得出全局结果

  3. 将当前批次的结果放入 StateStore 中, 留待下次使用

3.3 总结

  • StreamExecution 是整个 Structured Streaming 的核心, 负责在流上的查询

  • StreamExecution 中三个重要的组成部分, 分别是 Source 负责读取每个批量的数据, Sink 负责将结果写入外部数据源, Logical Plan 负责针对每个小批量生成执行计划

  • StreamExecution 中使用 StateStore 来进行状态的维护

3.4 我的笔记

1.RDD、DateFrame、DataSet的优缺点

2.一个Dataset在逻辑上表示什么?
就是一个表
怎么让它处理流式数据呢?
让表无线的网下延展,动态扩展的
(使用read创建的就是一个不能扩展的表格,使用readStream创建的就是一个可以无限扩展的表格)

StructuredStreaming的编程模型:
Source :读取数据源
  ↓
Query :再流式数据上查询
  ↓
Sink :结果集生成
我的理解:增量处理,计算出结果,再和原来的合并

3.无限扩展的表,这个模型很好,但是存在问题
DataFrame时间长了,会太大
不应该一直追加数据,而是处理增量的数据
(每一个批次处理完生成的结果,我们称为状态;
每个批次处理完保存下当前的最新的状态;
每个批次处理之前,拉出最新的状态,合并到处理过程中,一起处理,然后生成新结果)
这里的状态通过StateStore来实现

异常记录:
Exception in thread "main" org.apache.spark.sql.AnalysisException: Complete output mode not supported when there are no streaming aggregations on streaming DataFrames/Datasets;;
原因:使用OutputMode.Complete() 其操作必须要是聚合的操作 ,可以修改为:OutputMode.Append()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值