我正在尝试使用Kafka Source和Sink测试Flink一次精确的语义:
我希望无论TaskManager是否被杀死和恢复,输出主题中的整数都会单调增加。
但是实际上在控制台用户输出中看到了一些意外情况:
32
33
34
35
36
37
38
39
40
-- TaskManagerKilled
32
34
35
36
40
41
46
31
33
37
38
39
42
43
44
45
看起来像检查点之间在输出主题中重播的所有消息。 它应该是正确的行为还是我做错了什么?
已还原一个快照: Flink UI
我的Flink代码:
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.getConfig().setAutoWatermarkInterval(1000);
env.enableCheckpointing(20000, CheckpointingMode.EXACTLY_ONCE);
env.setStateBackend(new RocksDBStateBackend("hdfs:///checkpoints-data"));
Properties producerProperty = new Properties();
producerProperty.setProperty("bootstrap.servers", ...);
producerProperty.setProperty("zookeeper.connect", ...);
producerProperty.setProperty(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG,"10000");
producerProperty.setProperty(ProducerConfig.TRANSACTIONAL_ID_CONFIG,"my-transaction");
producerProperty.setProperty(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "true");
Properties consumerProperty = new Properties();
consumerProperty.setProperty("bootstrap.servers", ...);
consumerProperty.setProperty("zookeeper.connect", ...);
consumerProperty.setProperty("group.id", "test2");
FlinkKafkaConsumer<String> consumer1 = new FlinkKafkaConsumer<String>("stringTopic1", new ComplexStringSchema(), consumerProperty);
consumer1.assignTimestampsAndWatermarks(new PeriodicAssigner());
FlinkKafkaProducer<String> producer1 = new FlinkKafkaProducer<String>("test", new KeyedSerializationSchemaWrapper(new SimpleStringSchema()), producerProperty, FlinkKafkaProducer.Semantic.EXACTLY_ONCE);
producer1.ignoreFailuresAfterTransactionTimeout();
DataStreamSource<String> s1 = env.addSource(consumer1);
s1.addSink(producer1);
env.execute("Test");
}
答案 0 :(得分:1)
Flink定期生成可配置的检查点。恢复检查点后,Flink将状态回退到输入流中最后一个检查点的位置(不一定与上次处理/消耗的位置相同)。有多种方法可以确保一次语义。您可以使用支持一次语义的使用者(接收器),请参阅:Fault Tolerance Guarantees in Flink sinks。
或者,您可以在使用者中支持一次语义。假设使用多个工作程序持久存储的唯一整数(并行度> 1),确保一次处理的一种方法如下:
假定当前检查点ID为CkptN。以Ckpt N的状态存储所有已处理的整数(在大事件的情况下为已处理事件的指纹)。您可以通过让使用者实现ListCheckpointed接口进行存储来实现此目的。 Cppt N中的状态(指纹或您的情况下的整数)。
一旦Flink移至下一个检查点(Ckpt N + 1),将存储在Ckpt N状态下的所有整数过滤掉,以确保进行一次精确的处理。将未过滤的已处理整数(或已处理事件的指纹)存储为Ckpt N +1的状态(即丢弃Ckpt N的状态)。
您只需要存储在两个检查点之间发生的已处理事件(或您的情况下的整数)的指纹,并在以后保留新的检查点时将其丢弃。
答案 1 :(得分:1)
除了将生产者设置为一次语义之外,还需要将消费者配置为仅从kafka中读取已提交的消息。默认情况下,使用者将读取已提交和未提交的消息。将此设置添加到您的消费者可以使您更接近所需的行为。
consumerProperties.setProperty(ConsumerConfig.ISOLATION_LEVEL_CONFIG, "read_committed");