Exactly Once 语义在 Flink 中的实现 | 青训营笔记
这是我参与「第四届青训营 」笔记创作活动的的第4天
数据流和动态表
- 传统SQL和流处理:
| 特征 | SQL | 流处理 |
|---|---|---|
| 处理数据有界性 | 处理表是有界的 | 流是一个无限元组序列 |
| 处理数据完整性 | 执行查询可以访问完整的数据 | 执行查询无法访问所有数据 |
| 执行时间 | 批处理查询产生固定大小结果后终止 | 查询不断更新结果,永不终止 |
数据流和动态表转换:
Stream -> Dynamic Table -> Continuous Query ->Dynamic Table -> Stream Stream无界数据,转化为动态表,连续查询,再转化为动态表,最终转化为流。
在流上定义表:
动态表是随时间变化的,但处理的时候可以当作静态表处理。
连续查询:查询不终止,查询结果会不断更新
- SELECT user, COUNT(url) as cnt FROM clicks GROUP BY user
查询产生仅追加数据的动态表:
不更新之前时间点的数据,只追加新数据。统计某一时间段用户点击的次数。
- SELECT user, TUMBLE_END(cTime, INTERVAL '1' HOURS) AS endT, COUNT(url) AS cnt FROM clicks GROUP BY user, TUMBLE(cTime, INTERVAL '1' HOURS)
Retract消息的产生:对之前的数据更新时,会产生回撤消息,一次来进行更新
状态:统计用户当前的所有操作
不同数据处理保证的语义:
- at most-once:出现故障什么也不做,数据不保证任何语义,处理时延低
- at least-once:保证每一条数据处理一次,一条数据可能存在重复消费
- exactly-once:严格遵循处理语义,每条数据均被消费且消费一次,仿佛故障从未发生。
Exactly-once和Checkpoint
状态快照与恢复:
算子:读取数据流(source)、偶数累加器(sum_even)、奇数累加器(sum_odd)
对数据流的奇偶数编号进行累加,奇数编号进入sum_odd,偶数编号进入sum_even,当某一个累加器算子down掉时,保存breakdown之前的那条数据的快照,从图中看,奇数算子是加过5的,保存的值为9。待恢复后继续进行。
制作快照和时间点:
- 状态恢复时间点:等到所有处理逻辑消费完source保留的状态之前
- 一个简单的快照制作算法:
- 暂停处理数据
- 等待后续所有处理算子消费当前已经处理的数据
- 待2处理完后,作业所有算子复制自己的状态并保存到远端可靠服务器存储
- 恢复数据处理
快照制作Chandy-Lamport算法:
- 快照制作的开始:每一个source算子都接受到JM发送的Checkpoint Barrier标识状态快照制作的开始
- source算子的处理:source保存自己的状态后,向所有连接的下游继续发送Checkpoint Barrier,同时告诉JM自己状态已经制作完成 。
- Barrier Alignment:算子等待所有上有的barrier到达之后才开始制作快照,已经制作完成的上游算子会继续处理数据,并不会被下游算子制作快照的过程阻塞。
- 快照制作和处理数据的解耦:
- checkpoint的结束:所有算子告诉JM状态制作完成之后,结束checkpoint
checkpoint对作业性能的影响:
1.不用等待下游算子制作快照的时间 2.快照制作和BarrierAlignment过程需要暂停处理数据,仍会增加数据处理延迟 3.快照保存到远端可能极为耗时
flink端到端的Exactly-once语义
- 端到端的Exactly-once语义:checkpoint能抱保证每条数据都对各个有状态的算子更新一次,sink输出算子仍然可能下发重复的数据,严格意义的端到端Exactly-once语义需要特殊的sink算子实现
- 两阶段提交协议:引入中心节点统一处理所有节点的执行逻辑,这个节点叫做协作者,被中心节点调度的其他业务节点叫做参与者
(1)预提交阶段
(2)提交阶段
- flink种的2PC Sink