Exactly Once 语义在 Flink 中的实现 | 青训营笔记

75 阅读4分钟

Exactly Once 语义在 Flink 中的实现 | 青训营笔记

这是我参与「第四届青训营 」笔记创作活动的的第4天

数据流和动态表

  • 传统SQL和流处理:
特征SQL流处理
处理数据有界性处理表是有界的流是一个无限元组序列
处理数据完整性执行查询可以访问完整的数据执行查询无法访问所有数据
执行时间批处理查询产生固定大小结果后终止查询不断更新结果,永不终止

数据流和动态表转换:

Stream -> Dynamic Table -> Continuous Query ->Dynamic Table -> Stream Stream无界数据,转化为动态表,连续查询,再转化为动态表,最终转化为流。

在流上定义表:

capture_20220727102100614.bmp 动态表是随时间变化的,但处理的时候可以当作静态表处理。

连续查询:查询不终止,查询结果会不断更新

  • SELECT user, COUNT(url) as cnt FROM clicks GROUP BY user
  • capture_20220728111221076.bmp

查询产生仅追加数据的动态表:

不更新之前时间点的数据,只追加新数据。统计某一时间段用户点击的次数。

  • SELECT user, TUMBLE_END(cTime, INTERVAL '1' HOURS) AS endT, COUNT(url) AS cnt FROM clicks GROUP BY user, TUMBLE(cTime, INTERVAL '1' HOURS)
  • capture_20220728112059762.bmp

Retract消息的产生:对之前的数据更新时,会产生回撤消息,一次来进行更新

状态:统计用户当前的所有操作

不同数据处理保证的语义:

  • at most-once:出现故障什么也不做,数据不保证任何语义,处理时延低
  • at least-once:保证每一条数据处理一次,一条数据可能存在重复消费
  • exactly-once:严格遵循处理语义,每条数据均被消费且消费一次,仿佛故障从未发生。

Exactly-once和Checkpoint

状态快照与恢复:

capture_20220727104935582.bmp 算子:读取数据流(source)、偶数累加器(sum_even)、奇数累加器(sum_odd) 对数据流的奇偶数编号进行累加,奇数编号进入sum_odd,偶数编号进入sum_even,当某一个累加器算子down掉时,保存breakdown之前的那条数据的快照,从图中看,奇数算子是加过5的,保存的值为9。待恢复后继续进行。

制作快照和时间点:

  • 状态恢复时间点:等到所有处理逻辑消费完source保留的状态之前
  • 一个简单的快照制作算法:
    • 暂停处理数据
    • 等待后续所有处理算子消费当前已经处理的数据
    • 待2处理完后,作业所有算子复制自己的状态并保存到远端可靠服务器存储
    • 恢复数据处理

快照制作Chandy-Lamport算法:

capture_20220727105636944.bmp

  • 快照制作的开始:每一个source算子都接受到JM发送的Checkpoint Barrier标识状态快照制作的开始

capture_20220729152501872.bmp

  • source算子的处理:source保存自己的状态后,向所有连接的下游继续发送Checkpoint Barrier,同时告诉JM自己状态已经制作完成 。

capture_20220729152516135.bmp

  • Barrier Alignment:算子等待所有上有的barrier到达之后才开始制作快照,已经制作完成的上游算子会继续处理数据,并不会被下游算子制作快照的过程阻塞。

capture_20220729152531427.bmp

  • 快照制作和处理数据的解耦:

capture_20220729152545459.bmp

  • checkpoint的结束:所有算子告诉JM状态制作完成之后,结束checkpoint

capture_20220729152618674.bmp

checkpoint对作业性能的影响:

1.不用等待下游算子制作快照的时间 2.快照制作和BarrierAlignment过程需要暂停处理数据,仍会增加数据处理延迟 3.快照保存到远端可能极为耗时

flink端到端的Exactly-once语义

  • 端到端的Exactly-once语义:checkpoint能抱保证每条数据都对各个有状态的算子更新一次,sink输出算子仍然可能下发重复的数据,严格意义的端到端Exactly-once语义需要特殊的sink算子实现
  • 两阶段提交协议:引入中心节点统一处理所有节点的执行逻辑,这个节点叫做协作者,被中心节点调度的其他业务节点叫做参与者 (1)预提交阶段 capture_20220729095536514.bmp (2)提交阶段 capture_20220729095751210.bmp

capture_20220729095808064.bmp

  • flink种的2PC Sink

capture_20220729100012422.bmp

capture_20220729100319874.bmp

capture_20220729100334335.bmp

Flink案例讲解

  • capture_20220729100817626.bmp
  • capture_20220729100929894.bmp