Apache flink Flink检查点模式ExactlyOnce未按预期工作

Apache flink Flink检查点模式ExactlyOnce未按预期工作,apache-flink,flink-streaming,flink-cep,Apache Flink,Flink Streaming,Flink Cep,我是flink的新手,如果我的理解是错误的,我将构建一个数据流应用程序,并且该流包含多个数据流,这些数据流将检查传入数据流中是否存在必需的字段。我的应用程序验证传入的数据,如果数据验证成功,它应该将数据附加到给定文件中(如果数据已经存在)。我试图模拟一个数据流中是否发生任何异常,其他数据流不应受到影响,因为我在其中一个流中显式地抛出异常。为了简单起见,在下面的示例中,我使用windows文本文件来附加数据 注意:我的流没有状态,因为我没有任何东西要存储在状态中 public class Exce

我是flink的新手,如果我的理解是错误的,我将构建一个数据流应用程序,并且该流包含多个数据流,这些数据流将检查传入数据流中是否存在必需的字段。我的应用程序验证传入的数据,如果数据验证成功,它应该将数据附加到给定文件中(如果数据已经存在)。我试图模拟一个数据流中是否发生任何异常,其他数据流不应受到影响,因为我在其中一个流中显式地抛出异常。为了简单起见,在下面的示例中,我使用windows文本文件来附加数据

注意:我的流没有状态,因为我没有任何东西要存储在状态中

public class ExceptionTest {

    public static void main(String[] args) throws Exception {

        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // start a checkpoint every 1000 ms
        env.enableCheckpointing(1000);

       // env.setParallelism(1);

        //env.setStateBackend(new RocksDBStateBackend("file:///C://flinkCheckpoint", true));

        // to set minimum progress time to happen between checkpoints
        env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);

        // checkpoints have to complete within 5000 ms, or are discarded
        env.getCheckpointConfig().setCheckpointTimeout(5000);

        // set mode to exactly-once (this is the default)
        env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);  
        
        // allow only one checkpoint to be in progress at the same time
        env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);

        // enable externalized checkpoints which are retained after job cancellation
        env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);  // DELETE_ON_CANCELLATION

        env.setRestartStrategy(RestartStrategies.fixedDelayRestart(
                3, // number of restart attempts
                Time.of(10, TimeUnit.SECONDS) // delay
        ));

        DataStream<String> input1 = env.fromElements("hello");
        
        DataStream<String> input2 = env.fromElements("hello");


        DataStream<String> output1 = input.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public void flatMap(String value, Collector<String> out) throws Exception {
                //out.collect(value.concat(" world"));
                throw new Exception("=====================NO VALUE TO CHECK=================");
            }
        });


        DataStream<String> output2 = input.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public void flatMap(String value, Collector<String> out) throws Exception {
                out.collect(value.concat(" world"));
            }
        });

       output2.addSink(new SinkFunction<String>() {
           @Override
           public void invoke(String value) throws Exception {
               try {
                File myObj = new File("C://flinkOutput//filename.txt");
                if (myObj.createNewFile()) {
                    System.out.println("File created: " + myObj.getName());
                    BufferedWriter out = new BufferedWriter(
                            new FileWriter("C://flinkOutput//filename.txt", true));
                    out.write(value);
                    out.close();
                    System.out.println("Successfully wrote to the file.");
                } else {
                    System.out.println("File already exists.");
                    BufferedWriter out = new BufferedWriter(
                            new FileWriter("C://flinkOutput//filename.txt", true));
                    out.write(value);
                    out.close();
                    System.out.println("Successfully wrote to the file.");
                }
            } catch (IOException e) {
                System.out.println("An error occurred.");
                e.printStackTrace();
            }
           }
       });

        env.execute();

    }
  • 根据我在flink文档中的理解,如果我使用检查点模式,则不应将数据写入文件,因为该过程已经完成并将数据写入文件。但这并没有发生在我的情况下,如果我做错了什么,我也不会明白

  • 请帮助我澄清我对检查点的疑问,以及我如何实现我在flink中读到的关于两个阶段提交的完全相同的机制,但我没有得到任何关于如何实现它的示例

    根据@Mikalai Lushchytski的建议,我实现了下面的StreamingSink函数

    public class ExceptionTest {
    
        public static void main(String[] args) throws Exception {
    
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
            // start a checkpoint every 1000 ms
            env.enableCheckpointing(1000);
    
           // env.setParallelism(1);
    
            //env.setStateBackend(new RocksDBStateBackend("file:///C://flinkCheckpoint", true));
    
            // to set minimum progress time to happen between checkpoints
            env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
    
            // checkpoints have to complete within 5000 ms, or are discarded
            env.getCheckpointConfig().setCheckpointTimeout(5000);
    
            // set mode to exactly-once (this is the default)
            env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);  
            
            // allow only one checkpoint to be in progress at the same time
            env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
    
            // enable externalized checkpoints which are retained after job cancellation
            env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);  // DELETE_ON_CANCELLATION
    
            env.setRestartStrategy(RestartStrategies.fixedDelayRestart(
                    3, // number of restart attempts
                    Time.of(10, TimeUnit.SECONDS) // delay
            ));
    
            DataStream<String> input1 = env.fromElements("hello");
            
            DataStream<String> input2 = env.fromElements("hello");
    
    
            DataStream<String> output1 = input.flatMap(new FlatMapFunction<String, String>() {
                @Override
                public void flatMap(String value, Collector<String> out) throws Exception {
                    //out.collect(value.concat(" world"));
                    throw new Exception("=====================NO VALUE TO CHECK=================");
                }
            });
            
            
            DataStream<String> output2 = input.flatMap(new FlatMapFunction<String, String>() {
                @Override
                public void flatMap(String value, Collector<String> out) throws Exception {
                    out.collect(value.concat(" world"));
                }
            });
            
            
            String outputPath = "C://flinkCheckpoint";
    
            final StreamingFileSink<String> sink = StreamingFileSink
                    .forRowFormat(new Path(outputPath), new SimpleStringEncoder<String>("UTF-8"))
                    .withRollingPolicy(
                            DefaultRollingPolicy.builder()
                                    .withRolloverInterval(TimeUnit.MINUTES.toMillis(15))
                                    .withInactivityInterval(TimeUnit.MINUTES.toMillis(5))
                                    .withMaxPartSize(1)
                                    .build())
                    .build();
                    
            
            output2.addSink(sink);
    
           
           });
    
            env.execute();
    
        }
    
    公共类例外测试{
    公共静态void main(字符串[]args)引发异常{
    StreamExecutionEnvironment env=StreamExecutionEnvironment.getExecutionEnvironment();
    //每1000毫秒启动一个检查点
    环境启用检查点(1000);
    //环境(一);
    //环境设置状态后端(新RocksDBState后端(“file:///C://flinkCheckpoint“,对”);
    //设置检查点之间的最小进度时间
    env.getCheckpointConfig().setMinPausebetween检查点(500);
    //检查点必须在5000毫秒内完成,否则将被丢弃
    env.getCheckpointConfig().setCheckpointTimeout(5000);
    //将模式设置为恰好一次(这是默认设置)
    env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.justice_ONCE);
    //同时只允许一个检查点进行
    env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
    //启用作业取消后保留的外部化检查点
    env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);//删除_ON_CANCELLATION
    环境setRestartStrategy(restartStrategys.fixedDelayRestart(
    3,//重新启动尝试次数
    Time.of(10,TimeUnit.SECONDS)//延迟
    ));
    DataStream input1=env.fromElements(“hello”);
    DataStream input2=env.fromElements(“你好”);
    DataStream output1=input.flatMap(新的flatMap函数(){
    @凌驾
    公共void flatMap(字符串值,收集器输出)引发异常{
    //out.collect(value.concat(“世界”));
    抛出新异常(“==============================================================================================”);
    }
    });
    DataStream output2=input.flatMap(新的flatMap函数(){
    @凌驾
    公共void flatMap(字符串值,收集器输出)引发异常{
    out.collect(value.concat(“世界”));
    }
    });
    字符串outputPath=“C://flinkCheckpoint”;
    最终StreamingFileSink接收器=StreamingFileSink
    .forRowFormat(新路径(outputPath)、新SimpleStringEncoder(“UTF-8”))
    .使用滚动策略(
    DefaultRollingPolicy.builder()
    .带滚动区间(时间单位为分钟,单位为分钟(15))
    .withInactivityInterval(时间单位。分钟。托米利斯(5))
    .最大零件尺寸(1)
    .build())
    .build();
    输出2.添加接收器(接收器);
    });
    execute();
    }
    
    但是当我检查Checkpoint文件夹时,我可以看到它创建了四个部分的文件,如下所示


    我之所以这么做是因为它创建了多部分文件吗?

    为了保证端到端的精确一次记录传递(除了精确一次的状态语义之外),数据接收器需要参与检查点机制(以及数据源)

    如果要将数据写入文件,则可以使用,它将其输入元素发送到bucket中的
    文件系统
    文件。这与检查点机制集成在一起,以提供完全现成的语义

    如果要实现自己的接收器,那么接收器函数必须实现
    CheckpointedFunction
    接口,并正确实现
    snapshotState(FunctionSnapshotContext上下文)
    方法,该方法在请求检查点的快照并刷新当前应用程序状态时调用。此外,我建议实现
    CheckpointListener
    接口,一旦分布式检查点完成,就会收到通知

    Flink已经提供了一个抽象的
    TwoPhaseCommitSinkFunction
    ,它是所有打算实现一次语义的
    SinkFunction
    的推荐基类。它通过在
    CheckpointedFunction
    检查点侦听器
    。例如,您可以有一个
    public class ExceptionTest {
    
        public static void main(String[] args) throws Exception {
    
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
    
            // start a checkpoint every 1000 ms
            env.enableCheckpointing(1000);
    
           // env.setParallelism(1);
    
            //env.setStateBackend(new RocksDBStateBackend("file:///C://flinkCheckpoint", true));
    
            // to set minimum progress time to happen between checkpoints
            env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
    
            // checkpoints have to complete within 5000 ms, or are discarded
            env.getCheckpointConfig().setCheckpointTimeout(5000);
    
            // set mode to exactly-once (this is the default)
            env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);  
            
            // allow only one checkpoint to be in progress at the same time
            env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
    
            // enable externalized checkpoints which are retained after job cancellation
            env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);  // DELETE_ON_CANCELLATION
    
            env.setRestartStrategy(RestartStrategies.fixedDelayRestart(
                    3, // number of restart attempts
                    Time.of(10, TimeUnit.SECONDS) // delay
            ));
    
            DataStream<String> input1 = env.fromElements("hello");
            
            DataStream<String> input2 = env.fromElements("hello");
    
    
            DataStream<String> output1 = input.flatMap(new FlatMapFunction<String, String>() {
                @Override
                public void flatMap(String value, Collector<String> out) throws Exception {
                    //out.collect(value.concat(" world"));
                    throw new Exception("=====================NO VALUE TO CHECK=================");
                }
            });
            
            
            DataStream<String> output2 = input.flatMap(new FlatMapFunction<String, String>() {
                @Override
                public void flatMap(String value, Collector<String> out) throws Exception {
                    out.collect(value.concat(" world"));
                }
            });
            
            
            String outputPath = "C://flinkCheckpoint";
    
            final StreamingFileSink<String> sink = StreamingFileSink
                    .forRowFormat(new Path(outputPath), new SimpleStringEncoder<String>("UTF-8"))
                    .withRollingPolicy(
                            DefaultRollingPolicy.builder()
                                    .withRolloverInterval(TimeUnit.MINUTES.toMillis(15))
                                    .withInactivityInterval(TimeUnit.MINUTES.toMillis(5))
                                    .withMaxPartSize(1)
                                    .build())
                    .build();
                    
            
            output2.addSink(sink);
    
           
           });
    
            env.execute();
    
        }