java 实现 flink 读 kafka 写 iceberg

一.背景

在数据驱动决策的企业数字化转型进程中,业务对数据处理的核心诉求已从 "单纯的实时传输" 升级为 "实时采集 - 高效计算 - 长期可管 - 灵活复用" 的全链路能力。日志流、交易记录、设备采集数据等实时数据源持续爆发,这类数据既需要低延迟的实时处理以支撑即时决策(如实时监控、动态推荐),又需要长期可靠存储以满足离线分析、数据回溯、合规审计等场景,传统数据架构逐渐暴露 "实时与离线割裂、存储效率低、数据治理难" 的痛点。

传统架构中,实时数据常通过 Kafka 完成传输与暂存,但 Kafka 作为消息队列,仅适用于流式数据的短期流转,不支持复杂查询、数据更新、分层存储等能力,无法满足数据长期复用需求;而传统数据仓库(如 Hive)虽能承载离线分析,但写入延迟高、不支持高效的实时数据摄入,且难以应对半结构化 / 非结构化数据的存储诉求,导致 "实时处理结果无法高效沉淀,离线分析难以复用实时数据" 的割裂问题。同时,数据量的爆发式增长也对存储的成本控制、可扩展性、数据一致性提出了更高要求。

在此背景下,"Kafka + Flink + Iceberg" 的协同架构成为解决上述痛点的最优解之一,各组件各司其职、形成互补:

  1. Kafka 作为实时数据接入枢纽:凭借高吞吐、低延迟、高容错的特性,成为企业实时数据流的 "传输中枢",能够稳定承接日志、交易、传感器等多源实时数据的写入与分发,为后续计算提供持续、稳定的数据输入;
  2. Flink 作为流批一体计算引擎:具备强大的实时数据处理能力,支持 Exactly-Once 语义、复杂事件处理(CEP)、状态管理等核心特性,可高效消费 Kafka 中的实时数据流,完成数据清洗、转换、聚合、关联等计算逻辑,同时兼顾批处理场景,是连接 "实时数据源头" 与 "长期存储终端" 的核心计算桥梁;
  3. Iceberg 作为开放型数据湖存储方案:作为 Apache 顶级开源项目,Iceberg 提供了统一的表格式规范,兼具数据湖的灵活性与数据仓库的可靠性 ------ 支持实时写入、批量读取、ACID 事务、Schema 演进、时间旅行(数据回溯)、分区优化等核心能力,能够高效承接 Flink 处理后的实时数据,既满足低延迟的实时查询需求,又支持离线分析、数据归档、合规审计等场景,同时解决了传统数据湖 "数据混乱、查询低效、治理困难" 的痛点,实现数据的长期可管、可控、可复用。

Java 作为 Flink、Kafka、Iceberg 生态的核心开发语言,具备完善的 API 支持、成熟的企业级实践、丰富的生态工具链,能够确保架构的稳定性、可扩展性与可维护性。因此,采用 Java 实现 "Flink 读 Kafka 写 Iceberg" 的方案,本质是构建一套 "实时接入 - 流批一体计算 - 湖仓化存储" 的端到端数据处理闭环。该方案可广泛应用于实时数据仓库构建、用户行为全链路分析、金融交易实时归档与回溯、物联网数据实时处理与长期存储等业务场景,帮助企业打通实时与离线数据壁垒,实现数据价值的高效沉淀与灵活复用,同时降低数据存储与治理成本。

二.具体实现

1.创建java工程,配置依赖

复制代码
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-java</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-streaming-java</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-table-common</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-clients</artifactId>
      <version>1.18.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.flink</groupId>
      <artifactId>flink-connector-kafka</artifactId>
      <version>3.0.2-1.18</version>
    </dependency>
    <dependency>
      <groupId>org.apache.iceberg</groupId>
      <artifactId>iceberg-flink-runtime-1.18</artifactId>
      <version>1.5.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>hadoop-common</artifactId>
      <version>3.3.6</version>
    </dependency>

2.定义kafka数据源反序列化类

复制代码
public class DataSchemaDeserialization implements KafkaDeserializationSchema<ConsumerRecord<String,String>> {

    @Override
    public boolean isEndOfStream(ConsumerRecord<String,String> nextElement) {
        return false;
    }

    @Override
    public ConsumerRecord<String,String> deserialize(ConsumerRecord<byte[], byte[]> record) throws Exception {

        return new ConsumerRecord<String, String>(
                record.topic(),
                record.partition(),
                record.offset(),
                record.timestamp(),
                record.timestampType(),
                record.checksum(),
                record.serializedKeySize(),
                record.serializedValueSize(),
                record.key() != null ? new String(record.key()) : null,
                record.value() != null ? new String(record.value(), StandardCharsets.UTF_8) : null);
    }


    @Override
    public TypeInformation<ConsumerRecord<String,String>> getProducedType() {
        return TypeInformation.of(new TypeHint<ConsumerRecord<String,String>>() {
        });
    }
}

3.定义kafka数据源(json格式)

复制代码
Properties props = new Properties();
        props.put(CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,kafka地址);
        props.put(CommonClientConfigs.GROUP_ID_CONFIG,消费组);
        props.put(ENABLE_IDEMPOTENCE_CONFIG, "true");
 
        FlinkKafkaConsumerBase flinkKafkaConsumer = new FlinkKafkaConsumer<>(kafka topic, new DataSchemaDeserialization(), props).setStartFromGroupOffsets();

4.将kafka源转为RowData数据流

复制代码
DataStream<RowData> data = env.addSource(flinkKafkaConsumer).map(new MapFunction<ConsumerRecord, RowData>() {
            @Override
            public RowData map(ConsumerRecord value) throws Exception {


                GenericRowData row = new GenericRowData(10);

                       ... ...                             

                return row;
            }
        });

5.定义TableLoader

复制代码
        Configuration hadoopConf = new Configuration();

        TableLoader eventTableLoader = TableLoader.fromHadoopTable("hdfs://xxx", hadoopConf);

6.sink写入

复制代码
        DataStreamSink<Void> streamSink = FlinkSink.forRowData(data)
                .tableLoader(eventTableLoader)
                .append();
相关推荐
向上的车轮19 小时前
为什么.NET(C#)转 Java 开发时常常在“吐槽”Java:checked exception
java·c#·.net
Dragon Wu19 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
跳动的梦想家h19 小时前
环境配置 + AI 提效双管齐下
java·vue.js·spring
坚持就完事了19 小时前
Java中的集合
java·开发语言
wjhx19 小时前
QT中对蓝牙权限的申请,整理一下
java·数据库·qt
YCY^v^19 小时前
JeecgBoot 项目运行指南
java·学习
人间打气筒(Ada)19 小时前
jenkins基于Pipeline发布项目
java·pipeline·jenkins·流水线·ci·cd·cicd
爬山算法19 小时前
Hibernate(88)如何在负载测试中使用Hibernate?
java·后端·hibernate
自不量力的A同学19 小时前
Solon AI v3.9 正式发布:全能 Skill 爆发
java·网络·人工智能
万岳科技系统开发19 小时前
食堂采购系统源码库存扣减算法与并发控制实现详解
java·前端·数据库·算法