Exactly Once 语义在 Flink 中的实现笔记(一)| 青训营笔记
这是我参与「第四届青训营 -大数据场」笔记创作活动的的第4天
一、数据流和动态表
1. 传统SQL与流处理
| 特征 | SQL | 流处理 |
|---|---|---|
| 处理数据有界性 | 处理表有界 | 流是一个无限元组序列 |
| 处理数据的完整性 | 执行查询可以访问完整数据 | 查询无法访问所有的数据 |
| 执行时间 | 批处理查询产生固定大小结果后终止 | 查询不断更新结果,永不终止 |
2. 数据流和动态表的转换关系图
3. 算子状态
- 在流式计算中,会存在有状态的计算逻辑(算子),有状态的算子典型处理逻辑如下图所示:
比如,需要计算某个用户在网上的点击量,该用户在网站当前的总点击次数就是算子状态,对于新的输入数据,先判断是否是该用户的点击行为,如果是,则将保留的点击次数(状态)增加一,并将当前累加结果输出。
4. 如何在实时数据流中定义 SQL 语义中的表?
- 动态表 : 随时间不断变化的表,在任意时刻,可以像查询静态批处理表一样查询它们
- 数据流有新数据时,生成新的快照表
5. 实时流的查询特点
- 查询从不终止
- 查询结果会不断更新,并且会产生一个新的动态表
- 结果的动态表也可转换成输出的实时流
6. 连续查询
- 动态表-SQL->(对应当前快照的)动态表
- 流式查询,查询从不终止
- 查询结果会不断更新,产生一个新的动态表
- 在任何时候,连续查询的结果在语义上与以批处理模式在输入表快照上执行的相同查询的结果相同。
7. 查询产生仅追加数据的动态表
- 在TUMBLE WINDOW中统计一段时间内更新的内容
- 因为窗口不重叠所以不会更新之前的表
8. 连续查询和查询仅追加的对比
- 第一个查询更新之前输出的结果,定义结果表的changelog流包含INSERT和UPDATE
- 第二个查询只附加结果表,即结果表的changelog只包含INSERT
9. Retract消息的产生
- 通知下游需要先回撤之前已经发送的结果,然后发送新结果。
- 流式场景的特殊情况 需要回撤已经发送的数据流
10. 状态
- 需要存储每个用户的URL计数以便增加该计数并在输入表接受新行时发送新结果
- 为了保证后续正确,查询需要有状态,用来不断更新查询的结果
二、Exactly-Once 和 Checkpoint
1. 一致性保证语义
- At-most-once:每条数据消费至多一次,处理延迟低
- At-least-once:每条数据消费至少一次,一条数据可能存在重复消费
- Exactly-once:每条数据都被消费且仅被消费一次,仿佛故障从未发生
2. 状态快照及恢复
-
设置一个故障恢复的时间点——状态快照,一旦发生故障,只需要恢复到对应的时间点
- 记录当前数据流计算到的位点(source发送到的位置)
- 记录所有下游算子当前状态
- 保存到可靠的远端存储
3. 制作快照的时间点
-
状态恢复的时间点:需要等待所有处理逻辑消费完成source保留状态及之前的数据
-
一个简单的快照制作算法
- 暂停处理输入的数据
- 等待后续所有处理算子消费当前已经输入的数据
- 待处理完后,作业所有算子复制自己的状态并保存到远端可靠存储
- 恢复对输入数据的处理
-
需要停止作业处理逻辑,需要等待可能很漫长的时间,不方便实现
4. Chandy-Lamport算法
4.1 快照制作的开始
每一个source算子都接收到JobManager发送的一个Checkpoint Barrier标示状态快照制作的开始
4.2 Source算子的处理
各source保存自己的状态后,向所有连接的下游继续发送Checkpoint barrier,同时告知JobManager自己的状态快照已经制作完成。
- 完成自己的状态快照后source恢复处理后续数据,无需等待下游
4.3 Barrier Alignment
- 各个上游barrier通知会有先后
- 算子会等到所有上游的barrier到达后才开始快照的制作
- 已经制作完成的上游算子会继续处理数据,并不会被下游算子制作快照的过程阻塞
- 已经接收到barrier的上游如果继续给下游发送数据,下游会缓存起来而不会进行执行
- 类似过程也会发生到Sink
4.4 快照制作和处理数据的解耦
- 快照制作不需要所有部分停止处理,而每个算子只需要完成自己的快照并且传递barrier后即可恢复处理数据
4.5 checkpoint结束
- 所有下游算子全部通知JobManager快照制作完成,checkpoint结束
5. checkpoint对作业性能的影响
- 解耦了快照制作和数据处理过程,各算子制作完成状态快照后就可以正常处理数据,不用等待下游算子
- 在快照制作和barrier alignment过程中需要暂停处理数据,仍会增加数据处理延迟
- 快照保存到远端也可能极为耗时