flink的TwoPhaseCommitSinkFunction怎么做才能提供精准一次保证

背景

TwoPhaseCommitSinkFunction是flink中基于二阶段事务提交和检查点机制配合使用实现的精准一次的输出数据汇,但是想要实现精准一次的输出,实际使用中需要注意几个方面,否则不仅仅达不到精准一次输出,反而可能导致数据丢失,连至少一次的语义都不能达到

TwoPhaseCommitSinkFunction注意事项

TwoPhaseCommitSinkFunction是通过在两阶段提交协议实现的事务,大概简化为一下步骤:

1 在收到检查点分隔符的时候,开启事务,并把记录都写到开启的事务中,

  1. 开始进行状态的保存时,把检查点id对应的事务结束掉,做好准备提交的准备,并开启下一个事务
java 复制代码
public void snapshotState(FunctionSnapshotContext context) throws Exception {
        // this is like the pre-commit of a 2-phase-commit transaction
        // we are ready to commit and remember the transaction

        checkState(
                currentTransactionHolder != null,
                "bug: no transaction object when performing state snapshot");

        long checkpointId = context.getCheckpointId();
        LOG.debug(
                "{} - checkpoint {} triggered, flushing transaction '{}'",
                name(),
                context.getCheckpointId(),
                currentTransactionHolder);
		//当前检查点对应的事务做好准备,比如进行stream.flush等,准备好提交事务
        preCommit(currentTransactionHolder.handle);
        // 把当前检查点id对应的事务添加到状态中
        pendingCommitTransactions.put(checkpointId, currentTransactionHolder);
        LOG.debug("{} - stored pending transactions {}", name(), pendingCommitTransactions);

        currentTransactionHolder = beginTransactionInternal();
        LOG.debug("{} - started new transaction '{}'", name(), currentTransactionHolder);
        // 把当前检查点id对应的事务添加到状态中
        state.clear();
        state.add(
                new State<>(
                        this.currentTransactionHolder,
                        new ArrayList<>(pendingCommitTransactions.values()),
                        userContext));
    }
  1. 收到检查点完成的通知notify方法,提交第二步中检查点id对应的事务,注意这一步不是每次flink在进行检查点的时候都会通知,这种情况下,某一次的notify方法就需要把前几次的事务一起进行提交了,另外,如果提交某个检查点的事务失败,那么应用会重启,并且在重启后的initSnapshot方法中再次进行事务提交,如果还是失败,这个过程一直持续
java 复制代码
    public final void notifyCheckpointComplete(long checkpointId) throws Exception {
        Iterator<Map.Entry<Long, TransactionHolder<TXN>>> pendingTransactionIterator =
                pendingCommitTransactions.entrySet().iterator();
        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) {
        // 事务提交失败会抛出异常,导致job异常中止
            throw new FlinkRuntimeException(
                    "Committing one of transactions failed, logging first encountered failure",
                    firstError);
        }
    }

总结:

1。事务不能提交失败,如果失败会导致作业失败然后重新提交,如果最终没有成功提交,那么数据会丢失

2。数据库服务端的事务超时时间不能设置太短,不能仅仅大于检查点的间隔大小,原因是上面说的,flink有可能丢失检查点完成后的通知消息,所以服务端的事务超时时间要设置的足够大.

相关推荐
陈果然DeepVersion3 分钟前
Java大厂面试真题:Spring Boot+微服务+AI智能客服三轮技术拷问实录(六)
java·spring boot·redis·微服务·面试题·rag·ai智能客服
BeingACoder26 分钟前
【SAA】SpringAI Alibaba学习笔记(一):SSE与WS的区别以及如何注入多个AI模型
java·笔记·学习·saa·springai
DolphinScheduler社区27 分钟前
真实迁移案例:从 Azkaban 到 DolphinScheduler 的选型与实践
java·大数据·开源·任务调度·azkaban·海豚调度·迁移案例
liliangcsdn1 小时前
如何利用约束提示优化LLM在问题转sql的一致性
数据库·sql
zhangkaixuan4561 小时前
Apache Paimon 写入流程
java·大数据·apache·paimon
Java爱好狂.2 小时前
分布式ID|从源码角度深度解析美团Leaf双Buffer优化方案
java·数据库·分布式·分布式id·es·java面试·java程序员
Elastic 中国社区官方博客2 小时前
通过混合搜索重排序提升多语言嵌入模型的相关性
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
胡桃夹夹子2 小时前
存档111111111
java·开发语言
不会编程的小寒2 小时前
C++ 中string的用法
java·开发语言
乐悠小码2 小时前
Java设计模式精讲---02抽象工厂模式
java·设计模式·抽象工厂模式