flink学习日记3-DatastreamAPI(二)

27 阅读1分钟

输出算子

FileSink

  • 在指定路径文件夹中,每一个并行子任务都会输出自己的文件
  • 输出的文件可以通过OutputFileConfig来配置生成文件的前后缀
  • 可以配置文件滚动策略
  • 生成文件名中带有inprogress,说明这个文件是一个临时文件,还没有被commit,需要在检查点成功才会产生最终文件。所以需要设置checkpoint策略来确认写入
env.enableCheckpointing(2000, CheckpointingMode.EXACTLY_ONCE);
...数据读入、处理...
FileSink.DefaultRowFormatBuilder<Tuple2<String,Integer>> builder = FileSink.forRowFormat(new Path("outputs"), new SimpleStringEncoder<Tuple2<String,Integer>>())
                .withOutputFileConfig(OutputFileConfig.builder().withPartPrefix("test01").withPartSuffix("log").build())
                .withBucketAssigner(new DateTimeBucketAssigner<>("yyyy-mm-dd"))
                .withRollingPolicy(DefaultRollingPolicy.builder()
                        .withRolloverInterval(Duration.ofSeconds(10))
                        .withMaxPartSize(new MemorySize(1024 * 1024)).build());
        FileSink<Tuple2<String,Integer>> fileSink = builder.build();
​
        res.sinkTo(fileSink);

KafkaSink

  • 使用setBootstrapServers配置要连接的kafka集群
  • 使用setValueSerializationSchema进行更详细的序列化配置
  • 当DeliveryGuarantee配置为EXACTLY_ONCE时必须设置事务的前缀和checkpoint
KafkaSink<Tuple2<String, Integer>> kafkaSink = KafkaSink.<Tuple2<String, Integer>>builder().setBootstrapServers("addr:9192")
        .setRecordSerializer(KafkaRecordSerializationSchema.builder()
                .setTopic("quickstart-events")
                .setValueSerializationSchema(new SerializationSchema<Tuple2<String, Integer>>() {
                    @Override
                    public byte[] serialize(Tuple2<String, Integer> stringIntegerTuple2) {
                        StringBuilder builder = new StringBuilder();
                        builder.append("(" + stringIntegerTuple2.f0 + "," + stringIntegerTuple2.f1 + ")");
                        return builder.toString().getBytes(StandardCharsets.UTF_8);
                    }
                }).build())
        .setDeliveryGuarantee(DeliveryGuarantee.AT_LEAST_ONCE)
        .build();
​
res.sinkTo(kafkaSink);

JdbcSink

  • flink的1.18版本中,jdbc的输出算子仍使用旧版的addsink写法
  • 数据库连接信息在JdbcConnectionOptions中配置
  • 如果想立刻看到数据库更新,需要配置JdbcExecutionOptions(批量写入、重试配置)
ds.addSink(JdbcSink.sink("insert into test01.watersensor (id, ts, vc) VALUES (?,?,?)", (JdbcStatementBuilder<String>) (preparedStatement, s) -> {
    String[] strings = s.split(" ");
    preparedStatement.setObject(1,strings[0]);
    preparedStatement.setObject(2,Long.valueOf(strings[1]));
    preparedStatement.setObject(3,Integer.valueOf(strings[2]));
    System.out.println(preparedStatement);
}, JdbcExecutionOptions.builder()
        .withBatchSize(1)          // 1 条一刷
        .withBatchIntervalMs(0)    // 不等时间
        .withMaxRetries(3)
        .build(),
        new JdbcConnectionOptions.JdbcConnectionOptionsBuilder().withUrl("jdbc:mysql://addr:3306")
        .withDriverName("com.mysql.cj.jdbc.Driver")
        .withUsername("root")
        .withPassword("123456").build()));