这是我参与「第四届青训营」笔记创作活动的的第3天
一、数据流和动态表
SQL与流处理
处理数据有界性:SQL处理的表有界,流处理中流
数据流与动态表动态转换
- Stream -> Dynamic Table -> Continuous Query(连续查询) -> Dynamic Table -> Stream
- 动态表:随时间变化,可以像查询静态批处理表查询
二、Exactly-Once 和 Checkpoint
一致性保证语义
- At-most-once:每条数据消费至多一次,处理延迟低
- At-least-once:每条数据消费至少一次,一条数据可能存在重复消费
- Exactly-once:每条数据都被消费且仅被消费一次,仿佛故障从未发
Chandy-Lamport算法
分布式快照算法
checkpoint
Flink通过checkpoint机制实现故障前后的状态快照制作和恢复
三、端到端Exactly-Once实现
语义
- Checkpoint保证每条数据对各个有状态的算子更新一次,sink输出算子仍可能下发重复的数据
- Exactly-Once语义需要特殊的sink算子实现
两阶段提交协议(2PC)
分布式协议。在多个节点参与执行的分布式系统中,为协调每个节点都能同时执行或回滚某个事务性的操作,引入一个中心节点来统一处理所有节点的执行逻辑,中心节点叫协作者coordinator,被中心节点调度的其他业务节点叫参与者。 (一)预提交阶段
- 协作者向所有参与者发送一个commit消息
- 每个参与者收到消息后执行事务,但不真正提交
- 事务执行完成,发送一个成功的消息;执行失败发送失败的消息 (二)提交阶段
- 协作者向所有参与者发送一个commit消息
- 每个收到commit消息的参与者回滚事务的执行操作,并释放事务所占资源
- 完成2后,参与者发送一个ack消息给协作者
- 协作者收到所有参与者的ack消息后,标识事务成功并完成回滚
Flink 中的2PC Sink
- sink task向下游写数据前开启一事务,后续所有写数据在事务中执行,事务未提交前写入的数据下游不可读
- JM开始下发checkpoint barrier,当参与者接收到barrier后停止处理后续数据,对当前状态制作快照,状态制作成功则向JM发送成功的消息
- JM收到所有预提交成功的消息,则向所有处理逻辑发送可以提交此事务的消息,sink接受到消息后,则完成提交,下游可以读到事务写入的数据;若JM收到预提交失败的消息,通知所有处理逻辑回滚操作。
小结
- 支持两阶段提交协议的下游存储可以结合checkpoint机制实现严格意义上端到端的Exactly-Once
四、Flink案例讲解
账单计算服务:场景简介
所有账单消息往kafka下发,从kafka读取账单消息,进行处理后写入MySQL
执行方案
- 在上次记录的位点之后,从kafka中读取固定大小的数据
- 对该批数据去重和聚合
- 处理完成后写入MySQL中,若全部写入成功,记录当前读取到的消息的终点位置;若写入失败则不记录
- 跳回步骤重复执行
存在问题
- 非严格意义上的端到端exactly-once语义,若批数据处理完成后,在写入MySQL中发生异常则存在部分数据写入的情况,下次作业启动后这部分数据依然会重复写入
- 去重能力有限,只能在当前处理的一批数据内去重,批与批之间不可
flink解决方案优点
- 语义;下游读到的数据不丢不重
- 可在更长的时间维度对数据进行去重