Flink中实现Exactly one | 青训营笔记

75 阅读4分钟

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

数据流和动态表

传统SQL与流处理 image.png 动态表 : 随时间不断变化的表,在任意时刻,可以像查询静态批处理表一样查询它们。

实时流的查询特点:

  • 查询从不终止
  • 查询结果会不断更新,并且会产生一个新的动态表
  • 结果的动态表也可转换成输出的实时流

动态表到实时流的转换

  • Append-only Stream: Append-only 流(只有 INSERT 消息)
  • Retract Stream: Retract 流(同时包含 INSERT 消息和 DELETE 消息)
  • Upsert Stream:: Upsert 流(同时包含 UPSERT 消息和 DELETE 消息)

一致性保证语义

  • At-most-once:每条数据消费至多一次,处理延迟低
  • At-least-once:每条数据消费至少一次,一条数据可能存在重复消费
  • Exactly-once:每条数据都被消费且仅被消费一次,仿佛故障从未发生

Exactly-Once 和 Checkpoint

快照与恢复 image.png 状态恢复的时间点: 所有处理逻辑完成,source保存状态和先前数据。

快照制作:
image.png Source算子接收到JM发送的Barrier,开始制作->
source保存自身状态后,向下游发送barrier,告知JM完成->
所有算子都告知JM制作完成后,checkpoint结束。
(算子会等待所有上游barrier到达后才会开始快照制作。 上游算子制作完直接继续处理数据,与下游算子制作快照无关系)

Checkpoint 对作业性能影响

  1. 解耦了快照制作与数据处理过程,算子在处理完状态快照就可以正常处理数据。
  2. 制造快照和Barrier Alignment 过程中可能需要暂停,数据处理延迟可能增加。
  3. 快照保存到远端可能极为耗时。

端到端 Exactly-Once 实现

Checkpoint可以保证每条数据对各个有状态的算子更新一次,但sink输出仍然可能下发重复的数据。端到端 Exactly-Once还需要特殊的sink算子。

两阶段提交协议(2PC) image.png 多个节点参与执行的分布式系统中,为协调各个节点同时执行或者回滚事务性的操作,引入了一中心节点来统一处理其他节点的执行逻辑,中心节点叫协作者,其余被调度的叫参与者。

  • 预提交阶段
    协作者发送commit消息;
    参与者收到消息后,执行事务,但是不提交;
    若成功执行,则发送成功的消息,否则则发送失败的消息。

  • 提交阶段
    (若协作者成功收到所有参与者的yes)
    协作者发送commit消息;
    参与者收到消息后,释放资源,结束事务执行;
    之后参与者发送ack消息给协作者;
    协作者收到所有ack消息后,标识事务完成。\

    (若协作者收到参与者的no或超时)
    协作者发送rollback消息;
    参与者收到消息后,回滚事务执行操作,释放资源;
    之后参与者发送ack消息给协作者;
    协作者收到所有ack消息后,标识事务完成回滚。

Flink两阶段提交总结

  • 事务开启:
    在sink task向下游写数据之前,均会开启一个事务,后续所有写数据的操作均在这个事务中执行,事务未提交前,事务写入的数据下游不可读;

  • 预提交阶段:
    JM下发Barrier,当各个处理逻辑接收到barrier后停止处理后续数据,对当前状态制作快照,此时sink也不再当前事务下继续处理数据(处理后续的数据需要新打开下一个事务)。状态制作成功则向JM发送成功的消息,失败则发送失败的消息;

  • 提交阶段:
    若JM收到所有预提交成功的消息,则向所有处理逻辑(包括sink)发送可以提交此次事务的消息,sink接收到此消息后,则完成此次事务的提交。若JM有收到预提交失败的消息,则通知所有处理逻辑回滚这次事务的操作,sink丢弃这次事务提交的数据。

总结

本次课程更深一步对Flink执行方式进行了探讨,了解了Exactly-Once的实现方式和原理,以及Checkpoint的对作业性能的影响。