Flink状态一致性之exactly-once

幂等写入:

一个操作重复执行很多次,但只导致一次结果的更改,也就是说后面重复执行就不起作用了。eg:  pow(e,x)求多阶导还等于自己,HashMap,多次写入key相同的键值对等。

但需要注意的是,也会出现中间状态短暂的不一致,最终结果一致的情景。eg:flink的checkpoint还有流批结合做关联模型转换的ETL,这些不满足强一致性,但可实现最终一致性。

事务写入:

构建的事务对应着checkpoint,等到checkpoint真正完成的时候,才把所有对应的结果写入sink系统中,否则可回滚、撤销事务。

1. 预写日志(Write-Ahead-Log,WAL):把结果数据先当状态,提前在状态后端中缓存,然后在收到checkpoint完成的通知后,再一次性地写入到sink系统。

  • 特点:简单易实现、可适用于任何sink系统;但由于最后数据是按批处理写入,会存在延时;且按批写入的时候若没有做事务隔离,过程中发生故障恢复后就会导致重复写入。
  • 实现类:DataStream API提供了一个模板类GenericWriteAheadSink,来实现这种事务性sink。

2. 两阶段提交(Two-Phase-Commit,2PC):对于每个checkpoint,sink会让sink系统启动一个事务,然后将接受到的数据写入外部sink系统,但是不提交,只是"预提交"阶段,当jobmanager通知sink任务全部算子的checkpoint已经整合完成,sink任务才让sink系统正式提交事务,实现结果的真正写入。

  • 特点:真正实现了exactly-once;数据还是流式写入,不存在批处理的延时,且相比WAL额外开销小;但是对sink系统要求较高,需要外部系统支持事务,适应性不是很广泛。
  • 实现类:Flink提供了TwoPhaseCommitSinkFunction接口,实现较为复杂,需配置项比较多。

整个上下游状态一致性保证会受限于短板,根据木桶原理,端到端整体的一致性级别取决于最薄弱的那个环节。

接下来以kafka-flink-kafka为例,该组合可保证端到端的exactly-once:

注意:此场景下,kafka作为sink端需要开启readCommit的隔离级别。

猜你喜欢

转载自blog.csdn.net/LSur_king/article/details/115436298