flink读写kafka--写kafka

flink读写kafka--写kafka

介绍

主要介绍实际中flink如何读取写入设置kafka

flink版本:1.13.2

github地址:https://github.com/dahai1996/mdw-flink-quickstart


写入kafka

引入依赖

    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-connector-kafka_2.11</artifactId>
        <version>${flink.version}</version>
    </dependency>

包装下常用设置

public class SinkKafka {
    String topic;
    int kafkaProducersPoolSize;
    Properties propertiesSink = new Properties();

    /**
     * 获取kafka sink,该sink为string类型数据提供处理,需提交做好数据转换
     *
     * @param runEnv                 执行环境
     * @param requestTimeOutMs       超时时间,毫秒
     * @param topic                  写入的topic名
     * @param kafkaProducersPoolSize 覆盖默认生产者池大小,默认为5
     */
    public SinkKafka(RunEnv runEnv, String requestTimeOutMs, String topic, int kafkaProducersPoolSize) {
        propertiesSink.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, runEnv.getKafkaHost());
        propertiesSink.setProperty(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, requestTimeOutMs);
        this.topic = topic;
        this.kafkaProducersPoolSize = kafkaProducersPoolSize;
    }

    /**
     * 获取kafka sink,该sink为string类型数据提供处理,需提交做好数据转换
     *
     * @param runEnv           执行环境
     * @param requestTimeOutMs 超时时间,毫秒
     * @param topic            写入的topic名
     */
    public SinkKafka(RunEnv runEnv, String requestTimeOutMs, String topic) {
        propertiesSink.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, runEnv.getKafkaHost());
        propertiesSink.setProperty(ProducerConfig.REQUEST_TIMEOUT_MS_CONFIG, requestTimeOutMs);
        this.topic = topic;
        this.kafkaProducersPoolSize = 5;
    }

    /**
     * 获取kafka sink,使用默认序列化器
     * @param kafkaSerializationSchema 指定序列化器
     * @return 返回一个kafka sink
     */
    public FlinkKafkaProducer<String> getSink(KafkaSerializationSchema<String> kafkaSerializationSchema) {
        return new FlinkKafkaProducer<String>(
                topic,
                kafkaSerializationSchema,
                propertiesSink,
                FlinkKafkaProducer.Semantic.AT_LEAST_ONCE,
                kafkaProducersPoolSize);
    }

    /**
     * 获取kafka sink,使用默认序列化器
     * @return 返回一个kafka sink
     */
    public FlinkKafkaProducer<String> getSink() {
        return new FlinkKafkaProducer<String>(
                topic,
                new DefaultKafkaSerializationSchema(topic),
                propertiesSink,
                FlinkKafkaProducer.Semantic.AT_LEAST_ONCE,
                kafkaProducersPoolSize);
    }

    /**
     * 获取端到端一致性的kafka sink,使用默认序列化器
     * @param transactionTimeoutMs kafka事务提交时间,应该大于checkpoint时间间隔,小于kafka设置中transaction.max.timeout.ms(默认为15分钟)
     * @return 返回一个提供事务的kafka sink
     */
    public FlinkKafkaProducer<String> getExactlyOnceSink(String transactionTimeoutMs) {
        propertiesSink.setProperty(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG,transactionTimeoutMs);
        return new FlinkKafkaProducer<String>(
                topic,
                new DefaultKafkaSerializationSchema(topic),
                propertiesSink,
                FlinkKafkaProducer.Semantic.EXACTLY_ONCE,
                kafkaProducersPoolSize);
    }

    /**
     * 获取端到端一致性的kafka sink
     * @param transactionTimeoutMs kafka事务提交时间,应该大于checkpoint时间间隔,小于kafka设置中transaction.max.timeout.ms(默认为15分钟)
     * @param kafkaSerializationSchema 指定序列化器
     * @return 返回一个提供事务的kafka sink
     */
    public FlinkKafkaProducer<String> getExactlyOnceSink(String transactionTimeoutMs,KafkaSerializationSchema<String> kafkaSerializationSchema) {
        propertiesSink.setProperty(ProducerConfig.TRANSACTION_TIMEOUT_CONFIG,transactionTimeoutMs);
        return new FlinkKafkaProducer<String>(
                topic,
                new DefaultKafkaSerializationSchema(topic),
                propertiesSink,
                FlinkKafkaProducer.Semantic.EXACTLY_ONCE,
                kafkaProducersPoolSize);
    }

    public static class DefaultKafkaSerializationSchema implements KafkaSerializationSchema<String> {
        String topic;

        public DefaultKafkaSerializationSchema(String topic) {
            this.topic = topic;
        }

        @Override
        public ProducerRecord<byte[], byte[]> serialize(String element, @Nullable Long timestamp) {
            return new ProducerRecord<byte[], byte[]>(topic, element.getBytes(StandardCharsets.UTF_8));
        }
    }
}

使用

一般情况

FlinkKafkaProducer<String> sink1 = new SinkKafka(uat, "60000","topicName").getSink( );

自定义序列化

FlinkKafkaProducer<String> sink = new SinkKafka(uat, "60000", "topicName").getSink(
                new SinkKafka.DefaultKafkaSerializationSchema("topicName")
        );

注:DefaultKafkaSerializationSchema 使用utf-8序列化数据,返回string类型

端到端一致性设置

        FlinkKafkaProducer<String> sink2 = new SinkKafka(uat, "60000", "topicName").getExactlyOnceSink("60000");

注:这里表示,kafka写入数据的时候会有提交的动作,本质上就是一个标记。
在下一步处理的程序中中,读取kafka的设置中使用 setExactlyOnce()方法(见前文),表示读取有已提交标记的数据,就实现了端到端一致性。本质上是模拟两段式提交。

读取kafka时间戳作为水印


    /**
     * @param env         流执行环境
     * @param sourceKafka kafka数据源
     * @param duration    水印空闲时间
     * @param name        该步骤name
     * @return 一个带水印的kafka数据源,水印来自于kafka自带的时间戳
     */
    public static SingleOutputStreamOperator<String> getKafkaSourceWithMonotonousWatermarks(StreamExecutionEnvironment env, FlinkKafkaConsumerBase<String> sourceKafka, Duration duration, String name) {
        return env.addSource(sourceKafka).assignTimestampsAndWatermarks(WatermarkStrategy.<String>forMonotonousTimestamps().withIdleness(duration)).name(name);
    }

注:这里包装作为了常用方法。读取kafka的时间戳作为水印

注2:本质上是使用:

public final class RecordTimestampAssigner<E> implements TimestampAssigner<E> {
    public RecordTimestampAssigner() {
    }

    public long extractTimestamp(E element, long recordTimestamp) {
        return recordTimestamp;
    }
}

以此从消息中提取时间戳,这里kafka内部做了优化,帮助完善了内部实现。


posted @   sqhhhhAA111i  阅读(417)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示