Flink exactly-once 实战笔记

 

Flink-Kafka

众所周知,Flink在很早的时候就通过Checkpointing提供了exactly-once的semantic,不过仅限于自身或者是从KafkaConsumer中消费数据。而在Flink 1.4版本的时候加入了赫赫有名的TwoPhaseCommitSinkFunction,提供了End-to-End的exatcly-once语言,当然是在需要下游支持回滚的情况下,具体的概念和设计方式官网已经写的比较清楚,就不多加赘述。而对于KafkaProducer,Kafka在0.11版本之后支持transaction,也就意味着支持对写入数据的commit和rollback,在通过Flink写入到Kafka的应用程序中可以达到exactly-once的效果。

接下来展示一下如何在Flink应用程序中激活exactly-once语义。对于SourceFunction大家随意采用一种即可,文件,kafka topic等皆可。而主要部分是在于对FlinkKafkaProducer的初始化。我使用的是Flink1.7版本使用的Producer类为FlinkKafkaProducer011,观察它的构造函数,很容易发现有的构造函数中需要你传入一个枚举变量semantic, 有三种可选值NONEAT_LEAST_ONCE,EXACTLY_ONCE,而默认值为AT_LEAST_ONCE,很显然我们在这里需要使用EXACTLY_ONCE。不过在此之前,我们需要仔细阅读一下Flink官网Flink-kafka-connector的内容,其中提到,Kafka broker的transaction.max.timeout.ms默认为15分钟,而FlinkKafkaProducer011默认的transaction.timeout.ms为1个小时,远远超出了broker的最大超时时间,这种情况下如果你的服务挂了超过15分钟,就会造成数据丢失。所以如果需要你的producer支持的更长的事务时间就需要提高kafka broker transaction.max.timeout.ms的值。下面是一个简单的实例去使用Exactly-once语义的FlinkKafkaProducer。

FlinkKafkaProducer<String> producer = new FlinkKafkaProducer<>(
    topics,
    new KeyedSerializationSchemaWrapper<>(new SimpleStringSchema()),
    properties,
    FlinkKafkaProducer011.Semantic.EXACTLY_ONCE
)

这么做的话Flink sink到Kafka中在大部分情况下就都能保证Exactly-once。值得注意的是,所有通过事务写入的Kafka topic, 在消费他们的时候,必须给消费者加上参数isolation.level=read_committed,这是因为Kafka的事务支持是给写入的数据分为committed和uncomitted,如果使用默认配置的consumer,读取的时候依然会读取所有数据而不是根据事务隔离。

发布了357 篇原创文章 · 获赞 228 · 访问量 179万+

猜你喜欢

转载自blog.csdn.net/wangshuminjava/article/details/105247660