这是我参与「第四届青训营 」笔记创作活动的的第2天
1. 数据流和动态表
流式处理主要依靠的状态:
| 特点 | SQL | 流处理 |
|---|---|---|
| 有界性 | 有 | 无限元组序列 |
| 完整性 | 执行查询可以访问完整的数据 | 无法访问所有数据 |
| 执行时间 | 固定大小结果而终止 | 不断更新,永不终止 |
整体流程如下:
graph TD
Stream --> DynamicTable --> ContinuousQuery+State --> DynamicTable --> Stream
- 动态表的特点
- 随时间变化
- 在特定时间视为静态表,查询批处理,连续查询
- 查询方式(以点击网站次数为例):
- 不断对动态表进行计数更新;
- 不更新结果,设定时间间隔计数,只需要在表后插入数据;
- Retract:更新计数之前先回溯表格的内容
- 语义
- At-most-once:不管故障继续执行,处理时延低,准确性低
- At-least-once:至少处理一次,重复消费,准确性高
- Eactly-once:最严格,每条数据至少且最多消费一次。
2. Exactly-Once 和 Checkpoint
依赖状态快照与恢复
- 算法1:
- 暂停所有输入 -> 等待后续逻辑处理,上传快照 -> 恢复状态 -> 恢复对输入数据处理
- 时间点:等待处理逻辑消费完成source保留状态之前的数据
- Chandy-Lamport
- 快照制作开始:
JM向source发送Checkpoint Barrier。 - source算子处理:
停止处理,保存状态给state backend,向所有下游传输barrier; 继续处理后续数据。 - Barrier Alignment: 算子等待所有上游Barrier到达后才开始快照制作,上游数据到达会进行缓存;
- 所有算子告知JM状态完成,checkpoint结束
- 快照制作开始:
- 作业性能:
- 不用等下游算子全部制作完成
- 快照制作和Barrier Alignment依旧需要暂停,增加数据处理延迟
- 快照保存到远端,极为耗时
3. Flink 端到端Exactly-Once 实现
- 端到端Exactly-Once语义
- Checkpoint 保证每条数据对算子更新一次,但sink输出可能下发重复数据
- 严格意义需要特殊sink算子
- 两阶段提交协议
- 概念
多节点分布式,同时执行或者回滚某个事务性(全部执行或全部不执行)的操作;
协作者:引入中心节点统一处理节点的执行逻辑;
参与者:被中心节点调度的其他业务。 - 预提交阶段
- 协作者向参与者发送commit消息
- 参与者执行事务但不提交
- 执行成功与否,vote yes/no
- 提交阶段
- 所有vote yes
- 协作者发送commit;
- 参与者释放所需资源,结束事务执行;
- 发送ack消息给协作者;
- 协作者收到所有ack,标识事务执行完成。
- 有一个部分vote no
- 协作者向所有参与者发送rollback;
- 参与者收到rollback,回滚执行操作,并释放事务所占资源;
- 参与者发送ack给协作者;
- 协作者收到所有ack,标识事务完成回滚。
- 所有vote yes
- 概念
- Flink中2PC Sink
协作者:JobManager
参与者:eg data source,sink data
Kafka:消息队列;二维数组;数组无限长;有限;从队列头读,队列尾新增- pre commit
- checkpoint starts
Job manager 发布checkpoint barrier - without external state
传递barrier,状态保存到state backend - with external state in data sink
传递barrier,更新状态保存到state backend,传递给kafka,但kafka新增数据不可见
- checkpoint starts
- commit
- JM 发布给所有参与者 checkpoint completed
- sink向kafka commit 数据
- pre commit
- Conclusion
- 事务开启:sink task写入数据之前,开启事务,在事务中执行,未提交前所有数据不可读。
- 预提交阶段:JM发布checkpoint barrier,制作快照,sink不再继续处理数据(除非新开下一个事物),状态成功向JM提交消息。
- 提交阶段:所有成功消息后,向所有处理逻辑(含sink)发送可以提交此事务消息,sink完成提交,下游可写入数据;若收到失败,则通知所有处理逻辑回滚事务,sink丢弃此次数据。
- 缺点:延时高,在批处理或者流处理较小情况下应用
4. 案例讲解
- 账单计算服务
- 在上次记录位点之后,从Kafka(存在重复消息 at-least-once)读取固定大小的数据
- 批处理去重&融合
- 处理完成写入Mysql,成功记录终止为止,失败不记录位点
- 问题:
- 非严格意义的端到端Exactly-Once语义:
存在部分数据写入,可能在下次启动时数据重复写入,但Mysql可以避免重复写入 - 去重能力有限:
只能在一批数据内去重,无法在批与批之间去重
- 非严格意义的端到端Exactly-Once语义:
- 解决方案:Flink
从Kafka读取账单消息,进行处理后写入到MySQL- 严格意义的端到端Exactly-Once语义
- 增强的去重能力(更长时间维度):定时删除数据,设置保留时间
Conclusion
- 学习整体Flink中的处理逻辑,依靠动态表和数据流的相互转换
- 学习Exactly-once中算子通过barrier和JM相互交流实现
- 学习两阶段提交协议在Flink中实现Exactly-once,通过kafka的预处理和处理阶段中协作者与参与者的交流,保证数据输出可靠性
- 学习Flink的端到端的Exactly-once的实例应用