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

159 阅读4分钟

这是我参与「第四届青训营」笔记创作活动的第3天,学习内容为《Exactly Once语义在Flink中的实现》,包括数据流和动态表、Exactly-Once和Checkpoint、端到端Exactly-Once实现和Flink案例讲解。


本节课的重点为:数据流和动态表的转换、Checkpoint机制实现Exactly-Once语义(Chandy-Lamport算法)、端到端Exactly-Once实现(两阶段提交协议)。思维导图如下:

Exactly Once语义在Flink中的实现.png

数据流和动态表

  1. 数据流和动态表转换

image.png

  1. 动态表:随时间不断变化的表,在任意时刻,可以像查询静态批处理表一样查询它们;
  2. 连续查询:查询从不终止,查询结果会不断更新,产生一个新的动态表;
  3. 动态表到实时流的转换:包含Insert消息、Update消息、Retract消息;

Exactly-Once和Checkpoint

  1. 不同数据处理语义:
  1. At-most-once: 出现故障什么也不做,特点是处理时延低;
  2. At-least-once:保证每条数据至少被处理一次,存在重复消费现象;
  3. Exactly-once:每条数据被消费且仅消费一次,彷佛故障从未发生。
  1. 快照制作:Chandy-Lamport算法
  1. 开始:JM向下游所有source发送Checkpoint Barrier标识状态;
  2. Source收到Barrier后,保存自己状态到可靠存储中(Remote storage),然后向所有连接的下游继续发送Checkpoint Barrier,同时告知JM自己状态已经制作完成。完成Barrier下发后,会恢复数据处理(之前是停止的),即只关心自己快照制作完成就可以继续工作,无需等待下游处理
  3. 算子:等待所有上游的barrier(入边)到达才开始制作快照;快照制作完后会继续处理数据,不会被下游算子制作快照的过程阻塞
  4. 所有算子告知JM状态制作完成后,整个Checkpoint结束。
  1. Checkpoint对作业性能的影响:
  1. 解耦了快照制作和数据处理过程;
  2. 快照制作和Barrier Aligment过程需要暂停处理数据,仍然增加数据处理延迟,故障恢复也会增加数据处理延迟;
  3. 快照保存到远端也有可能极为耗时。

端到端Exactly-Once实现

  1. Checkpoint机制:只能实现每条数据对各个有状态的算子更新一次。即虽然有快照的制作和恢复,但是在快照制作过程中仍然会有部分数据往下发送。sink仍然可能下发重复的数据,因此需要特殊的sink算子实现严格意义的端到端Exactly-Once语义。
  2. 两阶段提交协议

image.png

  1. 协作者(coordinator,统一处理所有节点的执行逻辑)+参与者(participant,被中心节点调度的其他业务节点)
  2. 保证事务操作是原子性的,即要么都执行,要么都不执行
  3. 预提交阶段:所有参与者执行事务但不真的提交,事务执行是否成功反馈给协作者(vote yes/no)
  4. 提交阶段:若协作者收到所有参与者vote yes消息就让参与者执行事务所需的资源同时结束这次事务的运行,否则让所有参与者执行事务回滚操作
  1. 两阶段提交策略多用在离线方面或者数据集小的实时方面,因为当事务提交后,所有往下游的数据才对下游可见(在此之前下游也不能处理数据),则从事务开始到事务完全结束对下游来说存在一定的处理延迟,可能会阻碍整个数据处理逻辑。

Flink案例讲解

以账单计算服务为例(端到端Exactly-once场景)

  1. 传统:kafak->mysql+checkpoint(去重,聚合)->mysql(数据全部写入则记录当前读取到的消息的终止位置,否则不记录位点)
  2. 存在的问题:不能做到严格意义的端到端Exactly-once语义、去重能力有限;
  3. Flink解决方案

image.png

课程总结

  1. 数据流可以转换成动态表,动态表也能重新转换成数据流
  2. 处理无限数据流的算子可以是有状态的
  3. Flink通过Checkpoint机制实现故障前后的状态快照制作和恢复
  4. 支持两阶段提交协议的下游存储可以结合Flink Checkpoint机制实现严格意义上端到端的Exactly-once语义实现