当前位置:

首页 > 编程开发 > 自定义Flink KafkaSource读取键值对数据

自定义Flink KafkaSource读取键值对数据

本文详细阐述了如何在ApacheFlink中使用KafkaSource读取包含键(Key)的Kafka记录。通过实现自定义的KafkaRecordDeserializationSchema,用户可以完全访问ConsumerRecord对象,从而灵活地提取并处理记录的键、值、时间戳、分区、偏移量及其他元数据,克服了默认valueOnly反序列化器仅能获取记录值的局限性。

本文目录

    在Apache Flink中定制KafkaSource以读取键值对记录

    本文详细阐述了如何在 Apache Flink 中使用 `KafkaSource` 读取包含键(Key)的 Kafka 记录。通过实现自定义的 `KafkaRecordDeserializationSchema`,用户可以完全访问 `ConsumerRecord` 对象,从而灵活地提取并处理记录的键、值、时间戳、分区、偏移量及其他元数据,克服了默认 `valueOnly` 反序列化器仅能获取记录值的局限性。

    理解默认 valueOnly 反序列化器的局限性

    在使用 Apache Flink 的 KafkaSource 从 Kafka 读取数据时,常见的做法是利用内置的 KafkaRecordDeserializationSchema.valueOnly(StringDeserializer.class) 来反序列化记录。这种方法简单便捷,但它仅将 Kafka 记录的值部分反序列化为指定类型(例如 String),而忽略了记录的键、时间戳、分区、偏移量以及任何附加的头部信息。

    对于生产者以键值对形式发送的 Kafka 记录,例如通过 kafka-console-producer.sh --property "parse.key=true" --property "key.separator=:" 生产的数据,如果仅使用 valueOnly 反序列化器,我们将无法在 Flink 应用程序中获取到这些关键的键信息,也无法访问记录的时间戳等其他元数据。

    解决方案:实现自定义 KafkaRecordDeserializationSchema

    要解决上述局限性,核心在于实现一个自定义的 KafkaRecordDeserializationSchema。这个接口允许我们完全控制 Kafka ConsumerRecord 的反序列化过程。在 deserialize 方法中,我们可以直接访问到原始的 ConsumerRecord 对象,进而提取其键、值、时间戳等所有可用信息,并将其封装成 Flink 应用程序所需的任何自定义类型。

    1. 定义一个用于承载记录信息的POJO

    首先,我们定义一个简单的 Java POJO(Plain Old Java Object)来封装从 Kafka ConsumerRecord 中提取出的所有相关信息。这个POJO将作为自定义反序列化器的输出类型。

    import java.io.Serializable;
    
    public class KafkaRecordInfo implements Serializable {
        public String key;
        public String value;
        public Long timestamp;
        public String topic;
        public int partition;
        public long offset;
    
        // Flink 需要一个无参构造函数来进行序列化和反序列化
        public KafkaRecordInfo() {}
    
        public KafkaRecordInfo(String key, String value, Long timestamp, String topic, int partition, long offset) {
            this.key = key;
            this.value = value;
            this.timestamp = timestamp;
            this.topic = topic;
            this.partition = partition;
            this.offset = offset;
        }
    
        @Override
        public String toString() {
            return "KafkaRecordInfo{" +
                   "key='" + key + '\'' +
                   ", value='" + value + '\'' +
                   ", timestamp=" + timestamp +
                   ", topic='" + topic + '\'' +
                   ", partition=" + partition +
                   ", offset=" + offset +
                   '}';
        }
    }

    2. 实现自定义 KafkaRecordDeserializationSchema

    接下来,创建 KafkaRecordDeserializationSchema 的实现。在这个实现中,我们将重写 deserialize 方法来解析 ConsumerRecord,并重写 getProducedType 方法来声明输出类型。

    import org.apache.flink.api.common.typeinfo.TypeInformation;
    import org.apache.flink.connector.kafka.source.reader.deserializer.KafkaRecordDeserializationSchema;
    import org.apache.flink.util.Collector;
    import org.apache.kafka.clients.consumer.ConsumerRecord;
    
    import java.nio.charset.StandardCharsets;
    
    public class CustomKafkaRecordDeserializationSchema implements KafkaRecordDeserializationSchema {
    
        private static final long serialVersionUID = 1L; // 确保可序列化
    
        @Override
        public void deserialize(ConsumerRecord record, Collector out) throws Exception {
            // 提取键,如果键存在则转换为字符串,否则为null
            String key = (record.key() != null) ? new String(record.key(), StandardCharsets.UTF_8) : null;
            // 提取值,如果值存在则转换为字符串,否则为null
            String value = (record.value() != null) ? new String(record.value(), StandardCharsets.UTF_8) : null;
            // 提取时间戳
            Long timestamp = record.timestamp();
            // 提取主题
            String topic = record.topic();
            // 提取分区
            int partition = record.partition();
            // 提取偏移量
            long offset = record.offset();
    
            // 将提取的信息封装到 KafkaRecordInfo 对象中并发出
            out.collect(new KafkaRecordInfo(key, value, timestamp, topic, partition, offset));
        }
    
        @Override
        public TypeInformation getProducedType() {
            // 声明此反序列化器将生成 KafkaRecordInfo 类型的对象
            return TypeInformation.of(KafkaRecordInfo.class);
        }
    }

    3. 将自定义反序列化器集成到 KafkaSource

    最后,将这个自定义的 CustomKafkaRecordDeserializationSchema 实例传递给 KafkaSource.builder().setDeserializer() 方法。

    import org.apache.flink.api.common.eventtime.WatermarkStrategy;
    import org.apache.flink.streaming.api.datastream.DataStream;
    import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
    import org.apache.flink.connector.kafka.source.KafkaSource;
    import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
    
    public class FlinkKafkaKeyedRecordReader {
    
        public static void main(String[] args) throws Exception {
            // 设置 Flink 执行环境
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
            env.setParallelism(1); // 示例设置为单并行度
    
            String bootstrapServers = "localhost:9092"; // Kafka 集群地址
            String topic = "test3"; // 你的 Kafka 主题
            String groupId = "flink-consumer-group"; // 消费者组ID
    
            // 构建 KafkaSource,使用自定义的反序列化器
            KafkaSource source = KafkaSource.builder()
                    .setBootstrapServers(bootstrapServers)
                    .setTopics(topic)
                    .setGroupId(groupId)
                    .setStartingOffsets(OffsetsInitializer.earliest()) // 从最早的偏移量开始消费
                    .setDeserializer(new CustomKafkaRecordDeserializationSchema()) // 使用自定义反序列化器
                    .build();
    
            // 从 KafkaSource 创建数据流
            DataStream stream = env.fromSource(source, WatermarkStrategy.noWatermarks(), "Kafka Keyed Source");
    
            // 对接收到的数据进行处理和打印
            stream.map(recordInfo -> "Received from Kafka: Key=" + recordInfo.key +
                                     ", Value=" + recordInfo.value +
                                     ", Timestamp=" + recordInfo.timestamp +
                                     ", Topic=" + recordInfo.topic +
                                     ", Partition=" + recordInfo.partition +
                                     ", Offset=" + recordInfo.offset)
                  .print();
    
            // 执行 Flink 作业
            env.execute("Flink Kafka Keyed Record Reader");
        }
    }

    运行示例

    1. 启动 Kafka 和 Flink: 确保 Kafka 集群正在运行,并且 Flink 环境已准备就绪。
    2. 生产带键的 Kafka 消息: 使用 Kafka 控制台生产者发送带键的消息到 test3 主题:
      bin/kafka-console-producer.sh --topic test3 --property "parse.key=true" --property "key.separator=:" --bootstrap-server localhost:9092

      输入消息,例如:

      key1:valueA
      key2:valueB
      anotherKey:anotherValue
    3. 运行 Flink 应用程序: 编译并运行上述 FlinkKafkaKeyedRecordReader Flink 应用程序。你将在 Flink 任务管理器的日志中看到类似以下的输出:
      Received from Kafka: Key=key1, Value=valueA, Timestamp=1678886400000, Topic=test3, Partition=0, Offset=0
      Received from Kafka: Key=key2, Value=valueB, Timestamp=1678886401000, Topic=test3, Partition=0, Offset=1
      Received from Kafka: Key=anotherKey, Value=anotherValue, Timestamp=1678886402000, Topic=test3, Partition=0, Offset=2

      这表明 Flink 成功地读取并解析了 Kafka 记录的键、值和时间戳等信息。

    注意事项与扩展

    • 错误处理: 在 deserialize 方法中,如果 byte[] 无法正确转换为 String(例如,编码不一致),可能会抛出异常。在实际生产环境中,应加入健壮的错误处理逻辑,例如使用 try-catch 块,将解析失败的记录发送到死信队列,或者记录错误日志。
    • 数据类型转换: 示例中将键和值都转换为 String。如果 Kafka 记录的键或值是其他数据类型(例如 Avro、Protobuf、JSON),你需要在 deserialize 方法中引入相应的反序列化库和逻辑来解析 byte[]。
    • 访问头部信息: ConsumerRecord 还提供了 headers() 方法来访问 Kafka 记录的头部信息。如果你的生产者在记录中添加了自定义头部,你也可以在 deserialize 方法中提取并处理它们。
    • 性能考量: 自定义反序列化器会增加一些处理开销,但对于需要访问键或其他元数据的场景来说是必要的。对于高性能要求极高的场景,应确保反序列化逻辑尽可能高效。
    • Flink 版本兼容性: 本教程基于 Flink 1.15+ 版本,使用了 KafkaSource API。如果你使用的是较旧的 Flink 版本(如 Flink 1.11 或更早),可能需要使用 FlinkKafkaConsumer,其配置方式略有不同,但核心思想(实现 DeserializationSchema)是相同的。

    总结

    通过实现自定义的 KafkaRecordDeserializationSchema,Apache Flink 能够灵活且全面地处理来自 Kafka 的复杂记录结构,包括带键的记录、时间戳以及其他重要的元数据。这种方法为构建功能强大、数据解析精细的 Flink 流处理应用程序提供了坚实的基础。理解并掌握自定义反序列化机制是开发高级 Flink-Kafka 集成应用的关键一步。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    opencode安装skills教程及本地配置方法
    opencode安装skills教程及本地配置方法

    遇到OpenCode Skills无法加载或配置无效?本文手把手教你完成Skills的安装、环境变量设置及本地调试,避开常见坑点,让AI助手更懂你的代码习惯。

    如何开启Visual Studio2022实时代码分析警告提示
    如何开启Visual Studio2022实时代码分析警告提示

    解决 Visual Studio 2022 编辑时不显示代码分析警告的问题。指南涵盖 .NET 项目实时分析设置、Roslyn 分析器范围调整及错误列表来源筛选,确保开发者能高效利用实时代码诊断功能。

    如何在Visual Studio2022查看变量监视窗口调试程序
    如何在Visual Studio2022查看变量监视窗口调试程序

    详解 Visual Studio 2022 调试技巧:包括断点设置、监视窗口开启方法、变量添加步骤以及通过 F10 单步执行观察变量值变化的全过程。

    Visual Studio2017设置默认编码为UTF-8不带BOM
    Visual Studio2017设置默认编码为UTF-8不带BOM

    针对 Visual Studio 2017 缺乏全局默认编码选项的情况,详解如何利用 .editorconfig 设定项目级 UTF-8 无 BOM 规则,以及手动转换现有文件并校验字节的方法。

    Visual Studio2022F5调试提示启动项目未配置怎么修复
    Visual Studio2022F5调试提示启动项目未配置怎么修复

    解决 Visual Studio 2022 F5 调试报错问题,通过设置启动项目、检查解决方案属性及正确区分类库与应用项目,快速恢复调试功能。

    Visual Studio2022NuGet包还原失败离线处理方案
    Visual Studio2022NuGet包还原失败离线处理方案

    解决Visual Studio 2022离线环境中NuGet包还原失败的难题,涵盖依赖链分析、本地源配置、包集收集及隔离验证步骤,帮助开发者构建稳定的离线开发环境。

    Visual Studio2017大项目加载缓慢,优化加载性能技巧
    Visual Studio2017大项目加载缓慢,优化加载性能技巧

    解决Visual Studio 2017大型项目加载慢的实用指南。涵盖性能监测、扩展管理、文档恢复优化及版本兼容性检查,帮助开发者精准定位瓶颈并提升工作效率。

    Visual Studio2022设置多启动项目同时调试运行
    Visual Studio2022设置多启动项目同时调试运行

    详解 Visual Studio 2022 多启动项目配置方法,包括启动动作选择、顺序调整及调试技巧,帮助开发者高效调试分布式或前后端分离应用。

    fastapi下载文件接口实现教程
    fastapi下载文件接口实现教程

    深入解析在FastAPI框架中实现文件下载接口的完整方案,涵盖基于FileResponse的本地静态文件传输、基于StreamingResponse的分块流式传输、RFC 5987中文文件名编码规范、路径穿越安全防御及BackgroundTasks临时文件清理,并配备详细代码示例与架构解析图。

    码上飞 codeflying 平台功能介绍
    码上飞 codeflying 平台功能介绍

    了解码上飞CodeFlying如何利用自然语言生成应用。通过物品借用登记实例,学习需求解析、代码生成、测试优化及对话修改的核心操作流程。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。