[toc]
通用的流式处理概念
流式处理和离线处理
存在一个 USER_SCORES 表,在批处理和流式处理中分别执行 SELECT 语句,区别如下:
- 批处理一次返回最终结果
- 流处理会随着数据进入引擎,不断的输出结果(设定5s的winow触发计算)
什么是流式计算
流式计算的特点:
- 处理不断增长,理论上无限的数据集
- 持续的进行数据的处理
流式计算中时间域(Time domain)的概念
时间域通常区分为:
- 事件时间(Event Time),事件发生的时间
- 处理时间(Processing Time),引擎处理事件的系统时间
流式处理需要在一个指定的时间域中计算,大部分场景关心 Event time(观测真实世界的时间),例如:描述用户随时间的行为、大多数计费应用程序以及许多类型的异常检测。
时间偏差(Skew)
理想情况 Event time 和 Processing time 是相等的。现实情况中由于网络环境、分布式逻辑等原因,Event time 和 Processing time 通常存在偏差,如下图:
虚线表示理想情况,红色线表示现实情况,理想与红线之间的水平距离是处理时间和事件时间之间的偏离
时间窗口(Time Window)
沿着时间边界将数据集分割成有限的片段,对一个时间窗口的数据进行计算。时间窗口的打开和关闭由窗口分配器指定。
常见的几种时间窗口:
- Tumbling Windows(Time、Count)
- Sliding Windows(Time、Count)
- Session Windows
- Global Window
Tumbling Time Windows
固定时间长度,不重叠的窗口
Sliding Time Windows
固定时间长度,重叠的窗口
Session Windows
有特定模式(例如根据指定事件类型)指定窗口的开始和结束,不规则大小的窗口,窗口间的空隙称为 Session gap
水印(Watermark)
水印是一种关于事件时间的完整性的描述。代表引擎处理的时间进度。是一个时间戳x。具有值X的水印声明:已经观察到所有事件时间小于X的输入数据。
事件有序的情况
事件无序的情况
延迟消息的情况
可允许延迟(Lateness)
表示可以容忍数据迟到的程度。小于时间值x的时间,可能在Watermark更新为x后到达。在lateness范围内的数据还会参与计算(再次计算Window),超过的会被丢弃。
Flink中概念
Flink 架构和编程模型
架构可划分为以下几个部分和主要功能:
- JobManager
- ResourceManager
- Dispatcher
- JobMaster
- TaskManager
- Task Slots
- Client
- Submit
Tasks & Operator Chains(Streaming Dataflow)
类似 Spark 中的 Stage 划分
根据代码生产 Streaming Dataflow
根据算子特性,通过 Operator chain 划分 Task
Streaming Dataflow in parallelized view
在并行的视图中(假设 Source 并行度为 2),逻辑上的 Task 会被划分为两个 SubTask
Task Slots
定义一个TaskManager可以接受多少个Task(SubTask)。多个 Task Slots 平分TM的内存(资源只有内存隔离,没有CPU隔离)
假设两个 TaskManager 各3个 Task Slot,运行上面的 Streaming Dataflow,每个 Task Slot 中运行一个 SubTask。
Flink 允许多个 SubTask 共享一个 Slot,称为 Slot Sharing。当 Task/SubTask 很多时,没有足够的 Task Slot 保证一个 Task 占用一个 Task Slot 的情况。
有状态流处理(Stateful Stream Processing)
Flink 中的状态涉及到有状态的操作、系统容错等功能
有状态的操作(Stateful Operations):
- 应用程序搜索某些事件模式时,状态将存储到目前为止遇到的事件序列。
- 当聚合每分钟/小时/天的事件时,状态会保存挂起的聚合。
- 在数据流上训练机器学习模型时,状态保持模型参数的当前版本。
- 当需要管理历史数据时,状态允许有效地访问过去发生的事件。
程序容错(Fault Tolerant):Checkpointing 算法
- Checkpoint:运行时容错
- Savepoint:重新启动、迁移、升级。Manyally triggered checkpoint
与状态存储(State Persistence)有关的相关概念分类
- Key State vs. Operated State vs. Broadcast State
- Raw State vs. Managed State
- State TTL
- State Backend:Memory、FileSystem、RocksDB
- Queryable State(Beta)
Exactly Once vs. At Least Once
Flink 支持 Exactly-once 语义,针对的是应用内部的数据流处理(也就是State来说的)。
事件的处理可以发生多次,但是处理的结果只在持久化后端状态存储中反映一次,Flink 自身是无法保证端到端的 Exactly-once 语义的。所以基于Checkpoint重启处理,有些数据会重复处理(At Least once)
支持端到端的 Exactly-once:TwoPhaseCommitSinkFunction
Back Pressure
生成数据的速度大于算子消费的速度;
缓冲区(本地/远程)中的数据不能及时消费,数据进入缓冲区有阻塞。
Back Pressure in Flink
通过定时采样(Sample Threads,由 JobManager 触发):间隔50ms触发100次采样(默认)。得到一个 Ratio(0.01表示100个中有一个被压:无法写入缓冲区)
- OK: 0 <= Ratio <= 0.10
- LOW: 0.10 < Ratio <= 0.5
- HIGH: 0.5 < Ratio <= 1
Back Pressure in Spark Streaming(1.5.x+)
每个 Batch 计算一个平均速率,发送给上游控制速度。
Dynamic Table & Continuous Queries(SQL)
静态表:常规的数据库中的表或批处理中的表等,其在查询时数据不再变化
动态表:是随时间变化的,即使是在查询的时候。流上的数据是源源不断的,一条数据的到来会触发一次查询,这次查询在执行时还有下一条数据到来,对表本身数据是在变化的。
对动态表的查询是连续的,即连续查询(Continuous Query)
简单的GROUP-BY Count聚合查询
对应着下文介绍的Update查询,这种方式需要更新之前已经发出的结果,包括INSERT和UPDATE两种改变。改变之前已经发出的结果意味着,这种查询需要维护更多的状态(state)数据;
带有窗口(window)的聚合查询
对应着下文介绍的Append查询,这种方式查询的结果都是以追加的形式加入到result表中,仅包含INSERT操作。这种方式生成的表和update生成的表转换成流的方式不一样(见下文)
Dynamic Table to Stream
动态表转换为流或将其写入外部系统时,支持三种方法:
- Append-only Stream(仅追加)
- Retract Stream(回溯,undo-redo)
- Upsert Stream(redo)
Retract Stream(回溯,undo-redo)
Upsert Stream(redo)
Temporal Tables
Flink 1.13中改名 Versioned Table。可以提供历史某个时间点上的数据,在某些场景下可以避免重复计算。
有一个动态表 LatestRates
创建一个 Temporal Table Rate 记录 LatestRates 历史时间点上的数据。