Flink 状态一致性

状态一致性

什么是状态一致性

  • 有状态的流处理,内部每个算子任务都可以有自己的状态。

  • 对于流处理器内部(没有接入sink)来说,所谓的状态一致性,其实就是我们所说的计算结果要保证准确,一条数据不应该丢失,也不应该重复计算

  • 在遇到故障时可以恢复状态,恢复以后的重新计算,结果应该也是完全正常的。

状态一致性种类

  • 最多一次(At-Most-Once)

    • 任务发生故障时最简单的措施就是既不恢复丢失的状态,也不重放丢失的事件,所以至多一次是最简单的一种情况。

    • 它保证了每个事件至多被处理一次。

  • 至少一次(At-Least-Once)

    • 对于大多数现实应用而言,用户的期望是不丢事件,这类保障被称为至少一次。
    • 它意味着所有事件最终都会处理,虽然有些可能会处理多次。
  • 精确一次(Exactly-Once)

    • 精确一次是最严格,最难实现的一类保障。
    • 它不但能够保证事件没有丢失,而且每个事件对于内部状态的更新都只有一次。
    • Flink利用Checkpoints机制来保证精确一次语义。

端到端(end-to-end)状态一致性

端到端的保障指的是在整个数据处理管道上结果都是正确的。在每个组件都提供自身的保障情况下,整个处理管道上端到端的保障会受制于保障最弱的那个组件

那么端到端的精确一次在各部分又是如何实现的呢?

  • 内部:Checkpoints机制,在发生故障的时候能够恢复各个环节的数据。
  • Source:可设置数据读取的偏移量,当发生故障的时候重置偏移量到故障之前的位置。
  • Sink:从故障恢复时,数据不会重复写入外部系统。

其中前两种在上文已经介绍过了,下面就介绍一下Sink如何提供端到端的精确一次性保障。

Sink端到端状态一致性的保证

应用若是想提供端到端的精确一次性保障,就需要一些特殊的Sink连接器,根据情况不同,这些连接器可以使用两种技术来实现精确一次保障:

  • 幂等性写(idempotent write)

    - 幂等操作的含义就是可以多次执行,但是只会引起一次改变。 - 例如我们将相同的键值对插入一个哈希结构中就是一个幂等操作, 因为由于该键值对已存在后,无论插入多少次都不会改变结果。 - 由于可以在不改变结果的前提下多次执行,因此幂等性写操作在一定程度上减轻Flink检查点机制所带来的重复结果的影响

  • 事务性写(transactional write)

    • 事务性写其实就是原子性写,即只有在上次成功的检查点之前计算的结果才会被写入外部Sink系统。
    • 事务性写虽然不会像幂等性写那样出现重放过程中的不一致现象,但是会增加一定延迟,因为结果只有在检查点完成后才对外可见。
    • 实现思想:构建的事务对应着Checkpoints,待Checkpoints真正完成的时候,才把所有对应的结果写入Sink系统中。
    • 实现方式:
      • 预写日志(Write Ahead Log,WAL)
      • 两阶段提交(Two Phase Commit,2PC)

预写日志

  • 把结果数据先当成状态保存,然后在收到Checkpoints完成的通知时,一次性写入Sink系统。
  • 简单易于实现,由于数据提前在状态后端做了缓存,所以无论什么Sink系统都能用这种方式一批搞定。
  • 但同时它也存在问题,写入数据时出现故障则会导致一部分数据成功一部分失败。
  • DataStream API提供了一个模板类GenericWriteAheadSink,来实现这种事务性Sink。

两阶段提交

  • 对于每个Checkpoints,Sink任务会启动一个事务,并将接下来所有接收的数据添加到事务里。
  • 然后将这些数据写入外部 Sink,但不提交它们,这时只是“预提交”。
  • 当它收到Checkpoints完成的通知时,它才正式提交事务,实现结果的真正写入。
  • 这种方式真正实现了精确一次,它需要一个提供事务支持的外部Sink系统,Flink提供了TwoPhaseCommitSinkFunction接口。
  • 对外部Sink系统的要求
    • 外部Sink系统必须提供事务支持,或者Sink任务必须能够模拟外部系统上的事务。
    • 在Checkpoints的隔离期间里,必须能够开启一个事务并接受数据写入。
    • 在收到Checkpoints完成的通知之前,事务必须是“等待提交”的状态。在故障恢复的情况下,这可能需要一些时间。如果这个时候 Sink系统关闭事务(例如超时了),那么未提交的数据就会丢失。
    • Sink任务必须能够在进程失败后恢复事务。
    • 提交事务必须是幂等操作。

Flink+Kafka端到端状态一致性的保证

  • 内部:利用Checkpoints机制把状态保存,当发生故障的时候可以恢复状态,从而保证内部的状态一致性。

  • source 端:Kafka Consumer作为Source,可以将偏移量保存下来,当发生故障时可以从发生故障前的偏移量重新消费数据,从而保证一致性。

  • sink端:Kafka Producer作为Sink,采用两阶段提交Sink,需要实现一个TwoPhaseCOmmitSinkFunction

Built with Hugo
主题 StackJimmy 设计