Exactly Once 语义在 Flink 中的实现|青训营笔记
这是我参与「第四届青训营 」笔记创作活动的的第2天
1.0数据流和动态表
1.1目前流式数据
随处可见,银行、GPS、互联网……
1.2传统SQL和流处理
- 处理数据的有界性:有界--》无界
- 处理数据的完整性:可访问完整数据--》无法访问所有数据
- 执行时间:查询结束终止--》永不终止
1.3 数据流和动态表的转换
概念:表和流是可以动态转换的 例如:将用户操作流数据存储到表里
1.4连续查询
- 可以像查询静态批处理表一样查询动态表、连续查询(不终止、查询结果不断更新)
- 动态表-->[查询]-->新的动态表(持续更新)
1.5查询产生仅追加数据的动态表
- 例子:对连续没有重复的用户点击数据进行统计并追加到新的动态表
1.6两个连续查询对比
- 第一个查询会更新先前的查询结果
- 第一个查询会在先前的查询结果下面插入新的数据
1.7 Retract消息的产生
- 流式处理中有回撤消息的情况
- 部分存储(例如:MAP)可能处理不了add,只能set
1.8状态
- 统计每个用户URL计数,一便更新数据
1.9不同数据处理保证的语义
- At-most-once:每条数据至多做一次处理,出故障时啥都不做
- At-leat-once:保证每条数据至少被处理一次、一条数据可能存在重复消费
- Exactly-once:每条数据均被消费且仅消费一次,仿佛故障从未发生
2.0 Exactly-Once Checkpoint
2.1状态快照与恢复
- 恢复过程看似将算子恢复到状态中
2.2制作快照的时间点
- 并不能在任意时间点进行快照
- 状态恢复的时间点:需要等待所有处理逻辑消费完成source保留状态及之前的数据
- 一个简单的快照制作算法:暂停处理输入数据-->等待处理算子消费当前已经输入的数据-->待第二步处理完后,作业所有算子复制自己的状态并保存-->恢复对输入数据的处理
2.3 Chandy-Lamport
- 例子:奇数和偶数累加器
2.3.1快照制作的开始
- 由JM下发 Checkpoint Barrier到source
2.3.2 source算子的处理
- source(进行Checkpoint Barrie下发,告知JM)
2.3.3 Barrier Alignment
- 算子会会缓存不会处理,等待所有barrier到达才开始快照制作,
2.3.4快照制作和处理数据的解耦
- Sink不会下发了(后面没有节点),处理完会告诉JM
2.3.5 checkpoint的结束
- 所有算子都告知JM状态制作完成则结束
2.4 Checkpoint
- 解耦了快照制作和数据处理过程
- 仍然会增加数据处理延时
- 快照保存到远端也可能极为耗时
- 由于消费比较大要做到端到端还要进一步处理
3.0 Flink端到端的Exactly-once语义
3.1两阶段提交协议
- 协作者(coordinator):计算逻辑分部在多个机器中,保证每个节点同时执行或回滚某个事务性操作引入的一个中心节点用来统一处理所有节点的执行逻辑
- 参与者(participate):被中心节点调用的其他业务节点
3.1.1阶段一:预提交阶段
- 协作者发生commit消息——>参与者执行事务,不真正提交-->事务执行成功(vote yes)或失败发生消息
3.1.2阶段二:提交阶段
- 若COO收到所有的VOTE yes则发送commit-->参与者释放执行事务的资源-->发送ack给协作者-->协作者收到所有ack则结束
- 若收到参与者的VOTE no则发送rollback………………
3.2Flink中2PC Sink
JM State Backend
Kafka-->DATA source-->Window-->Data Sink-->kafka
3.3 Flink 两阶段提交总结
事务开启(Sink Task向下游写数据前,均开启一个事务,事务写入的数据下游不可读)-->预提交阶段-->提交阶段(JM通知提交,则Sink完成事务的提交,此时下游可以读到这次事务导入的数据。如果JM有收到预提交失败的消息,则通知所有处理逻辑回滚这次事务操作)
缺点:增加时延
4.总结
- 数据流可以转换成动态表。动态表也能重写转换成数据流
- 处理无限数据流的算子可以是有状态的
- Flink通过Checkpoint机制实现故障前后的状态快照制作和恢复
- 支持两阶段提交协议的下游存储可以结合Flink Checkpoint机制实现严格意义上端到端的Exactly-Once语义实现