Flink 全局快照, 恢复, 二段提交

Flink global snapshot, restore, two-phase commit

快照原理

  • chandy Lamport算法的一种变体被称为异步屏障快照

  • 容错机制-障碍的实现原理

主要是通过不断生成快照来实现。快照主要包含两部分数据,一部分是数据流,另一部分是状态数据。

相应的快照机制有两个组成部分: Barrier和State。因为数据在DAG中流动,所以需要满足它以获取快照。在此时间之前的所有数据都被处理,在此时间之后的数据都不被处理.

Barrier 原理

一个Stream barrier 被插入到数据流中,并与数据一起流动,带有快照id。

一旦接收操作符收到所有输入数据流的barrier n,它将向检查点协调器发送一个快照 n 确认。当所有sink都确认快照 n 时,系统认为当前n的快照已经完成
在这里插入图片描述

Alignmen 机制

快速数据流将存储在运算符的输入缓冲区中。当所有屏障到达后,先对缓冲区中的数据进行处理,再进行处理。
在这里插入图片描述

事务 - 二阶段提交

  • 简要介绍

它是最基本的分布式一致性协议

引入一个中心节点来对所有节点的执行逻辑和进度达成一致,其他节点称为参与者

  • 过程

  • 请求阶段

    • 协调器将准备请求和事务内容发送给所有参与者,询问是否可以准备事务提交,并等待参与者的响应。

    • 参与者在事务中执行操作,并记录撤消日志(用于回滚)和重做日志(用于重播),但不实际提交。

    • 参与者将事务的执行结果返回给协调器。如果执行成功,则返回yes。否则,返回no

  • 提交阶段(分为成功和失败)

  • 如果所有参与者都返回yes,则可以提交事务。

    • 协调器向所有参与者发送提交请求。

    • 参与者收到提交请求后,提交事务,释放已占用的事务资源,并向协调器返回一个ack。

    • 协调器接收来自所有参与者的ack消息,事务成功完成。

    • 如果参与者返回no或不返回超时时间,则事务将被中断并需要回滚。

    • 协调器向所有参与者发送回滚请求。

    • 参与者收到回滚请求后,根据undo日志回滚到事务执行前的状态,释放已占用的事务资源,并向协调器返回ack。

    • 协调器接收来自所有参与者的ack消息,事务回滚完成。

2pc(二阶段提交)的优缺点

优势

  • 原理简单,易于理解和实现

缺点

  • 协调器 coordinator 有一个单点问题

  • 在大并发下存在阻塞问题,因为它是一个同步进程

  • 存在由提交失败引起的不一致

基于2PC应用的flink

  • flink的内部意图检查点机制和轻量级分布式快照算法ABS保证了精确一次。其次,如果我们想要实现端到端精确的一次性输出逻辑,我们需要施加以下两个限制之一: 幂等写和事务性写。

TwoPhaseCommitSinkFunction(基于2PC)帮助我们做一些基本的工作

  • Flink官方建议所有需要确保只继承这个抽象类一次的接收逻辑。它具体定义了以下四个抽象方法。我们需要在子类中实现它。
//Start a transaction and return the handle of transaction information
	protected abstract TXN beginTransaction() throws Exception;
	//Logic of the pre submit (i.e. submit request) phase   
	protected abstract void preCommit(TXN transaction) throws Exception;
    //Logic of formal submission phase
    protected abstract void commit(TXN transaction);
    //Cancel transaction
    protected abstract void abort(TXN transaction);
  • 2PC在flink和kafka集成中的具体过程

(只有kafka0.11及以上版本支持幂等生产者和事务,所以2PC有存在的意义)

kafka的事务和幂等引用。

  • Flink 的实现

    //FlinkKafkaProducer011. The commit () method actually proxies kafkaproducer The committransaction () method formally submits the transaction to Kafka.
    	@Override
        protected void commit(KafkaTransactionState transaction) {
            if (transaction.isTransactional()) {
                try {
                    transaction.producer.commitTransaction();
                } finally {
                    recycleTransactionalProducer(transaction.producer);
                }
            }
        }
    //The call point of this method is located at twophasecommitsinkfunction In the notifycheckpointcomplete () method, as the name suggests, this method will be called when all checkpoints are successful.
    @Override
        public final void notifyCheckpointComplete(long checkpointId) throws Exception {
            Iterator<Map.Entry<Long, TransactionHolder<TXN>>> pendingTransactionIterator = pendingCommitTransactions.entrySet().iterator();
            checkState(pendingTransactionIterator.hasNext(), "checkpoint completed, but no transaction pending");
            Throwable firstError = null;
            while (pendingTransactionIterator.hasNext()) {
                Map.Entry<Long, TransactionHolder<TXN>> entry = pendingTransactionIterator.next();
                Long pendingTransactionCheckpointId = entry.getKey();
                TransactionHolder<TXN> pendingTransaction = entry.getValue();
                if (pendingTransactionCheckpointId > checkpointId) {
                    continue;
                }
    
                LOG.info("{} - checkpoint {} complete, committing transaction {} from checkpoint {}",
                    name(), checkpointId, pendingTransaction, pendingTransactionCheckpointId);
    
                logWarningIfTimeoutAlmostReached(pendingTransaction);
                try {
                    commit(pendingTransaction.handle);
                } catch (Throwable t) {
                    if (firstError == null) {
                        firstError = t;
                    }
                }
                LOG.debug("{} - committed checkpoint transaction {}", name(), pendingTransaction);
                pendingTransactionIterator.remove();
            }
            if (firstError != null) {
                throw new FlinkRuntimeException("Committing one of transactions failed, logging first encountered failure",
                    firstError);
            }
        }
    
    • 从代码中可以看出,该方法每次都从等待提交的事务句柄中取出一个,检查它的检查点ID,并调用commit()方法提交。该阶段的流程图如下:
      在这里插入图片描述

    • 可以看到,只有当所有检查点都成功时,写操作才会成功。这与前面描述的2PC过程是一致的。Jobmanager是协调器,每个操作符是参与者,sink中的一个参与者将执行提交。一旦检查点失败,notifyCheckpointComplete()方法将不会被执行。如果重试失败,将初始化重试。最后,调用abort()方法来回滚事务。

    @Override
        protected void abort(KafkaTransactionState transaction) {
            if (transaction.isTransactional()) {
                transaction.producer.abortTransaction();
                recycleTransactionalProducer(transaction.producer);
            }
        }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值