Flink一致性保证实现剖析

本文深入探讨Flink如何通过快照和Barrier实现一致性保证。在EXACTLY_ONCE模式下,Flink通过快照记录task/Operator状态,利用 Barrier 对输入流进行划分,确保数据在operator状态中只被重放一次。同时,文章介绍了AT_LEAST_ONCE模式的特点,并讨论了Barrier的核心作用,以及在不同模式下状态管理的差异。
摘要由CSDN通过智能技术生成

概述

Flink通过快照机制和Barrier来实现一致性的保证,当任务中途crash或者cancel之后,可以通过checkpoing或者savepoint来进行恢复,实现数据流的重放。从而让任务达到一致性的效果,这种一致性需要开启exactly_once模式之后才行。需要记住的是这边的Flink exactly_once只是说在Flink内部是exactly_once的,并不能保证与外部存储交互时的exactly_once,如果要实现外部存储连接后的exactly_once,需要进行做一些特殊的处理。Flink定义的checkpiont支持两种模式(CheckpointingMode):

  • EXACTLY_ONCE
  • AT_LEAST_ONCE

EXACTLY ONCE

该模式意味着系统在进行恢复时,每条记录将在Operator状态中只被重现/重放一次。例如在一段数据流中,不管该系统crash或者重启了多少次,该统计结果将总是跟流中的元素的真实个数一致。

当然EXACTLY_ONCE并不是说毫无确定,相比较AT_LEAST_ONCE,整体的处理速度会相对比较慢,因为在开启EXACTLY_ONCE后,为了保证一致性开启了数据对齐,从而影响了一些性能。

AT LEAST ONCE

该模式意味着系统将以一种更加简单的方式来对operator的状态进行快照,系统crash或者cancel后恢复时,operator的状态中有一些记录可能会被重放多次。

例如,以上面的例子讲说,失败后恢复时,统计值将等于或者大于流中元素的真实值。这种模式因为不需要对齐所有对延迟产生的影响很小,处理速度也更加快速,通常应用于接收低延时并且能够容忍重复消息的场景。

一致性实现原理

虽然上面讲到了一致性的保证是通过快照和Brrier机制来实现的,那他们具体是如何实现的呢?阅读中可以通过带入以下几点来进行考虑:

  1. 快照中保存的是什么?
  2. 什么时候触发系统进行执行快照?
  3. 如何在流式计算中既要执行快照又要保证整体的处理速度?

CHECKPOINT

快照记录了系统当前各个task/Operator的状态,这些状态保存了正常处理的元素。这些快照将被定期的删除和更新,系统出现crash后,进行恢复时就会从这些快照中读取数据,恢复crash之前的状态,那么该如何理解状态(STATE)呢?

STATE

State 可以理解为某task/operator在某时刻的一个中间结果,比如在flatmap中在这段时刻处理的数据,State可以被记录,在系统失败的情况可以进行恢复。STATE主要有两种类型operator state和keyed state。

OPERATOR STATE和KEYED STATE

Operator state是一个与key无关,并且在全局中唯一绑定到特定的operator中的state,比如有source或者map算子,如果需要保存这些operator的状态,就可以在这些operator添加状态的处理机制,具体可以看下面的例子。

Operator state只有一种数据结构ListState<T>,具体checkpoint过程中会把该数据结构的数据写入到hdfs中,用于保存该operator在当前的状态。

Keyed State:

  • 基于KeyStream之上的状态,如dataStream.keyBy()
  • keyby之后的operator state

keyed state的数据结构:

  • ValueState<T>
  • LisstState<T>
  • ReducingState<T>
  • MapState<UK,UV>

CHECKPOINT实现例子

这是operator state实现的例子

public class BufferingSink implements SinkFunction<Tuple2<String,Integer>>,CheckpointedFunction {
    private final int threshold;
    private transient ListState<Tuple2<String,Integer>> checkpointedState;
    private List<Tuple2<String,Integer>> bufferedElements;

    public BufferingSink(int threshold) {
        this.threshold = threshold;
        this.bufferedElements = new ArrayList<Tuple2<String, Integer>>();
    }
    @Override
    public void invoke(Tuple2<String, Integer> value, Context context) throws Exception {
        bufferedElements.add(value);
        if(bufferedElements.size() == threshold){
            for(Tuple2<String,Integer> element:bufferedElements){
                //send it to the sink
            }
            bufferedElements.clear();
        }
    }
    @Override
    public void snapshotState(FunctionSnapshotContext functionSnapshotContext) throws Exception {
        /**定期实现checkpoint*/
        checkpointedState.clear();
        for(Tuple2<String,Integer> element:bufferedElements){
            checkpointedState.add(element);
        }
    }
    /**恢复初始化的时候从保存的快照中获取数据,用于恢复到crash之前的状态*/
    @Override
    public void initializeState(FunctionInitializationContext context)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值