java 实现 flink 读 kafka 写 paimon

一.背景

在数字化转型加速的当下,企业业务场景日益复杂,数据呈现出 高并发、低延迟、多源异构 的核心特征。日志采集、交易流水、用户行为等实时数据源源不断产生,这类数据不仅需要被快速接收、处理,更需要长期存储以便后续离线分析、数据回溯与合规审计,形成 "实时处理 + 离线复用" 的完整数据闭环。

传统数据处理架构中,实时数据常通过消息队列(如 Kafka)暂存,但 Kafka 仅适用于流式数据的临时存储与传输,不支持高效的离线查询、数据更新与分层管理;而传统数据仓库(如 Hive)虽能满足离线分析需求,却难以应对实时数据的低延迟处理诉求,导致 "实时处理" 与 "长期存储" 脱节,无法兼顾业务对数据时效性和复用性的双重要求。

在此背景下,各类组件的协同架构成为解决该痛点的关键:

  1. Kafka 作为实时数据接入层:凭借高吞吐、低延迟、高容错的特性,Kafka 已成为企业实时数据流转的核心枢纽,承担着日志、交易、传感器等实时数据流的接收与分发任务,是实时数据处理的 "数据源头";
  2. Flink 作为实时计算引擎:Flink 具备强大的流批一体处理能力,支持 Exactly-Once 语义、复杂事件处理(CEP)、状态管理等核心特性,能够高效消费 Kafka 中的实时数据流,完成数据清洗、转换、聚合、关联等计算逻辑,是连接 "数据源头" 与 "存储终端" 的核心计算桥梁;
  3. Paimon 作为湖仓存储层:Paimon(原 Flink Table Store)作为开源湖仓一体存储方案,兼具数据湖的灵活性与数据仓库的高效查询能力,支持实时写入、批量读取、数据更新、分区管理、索引优化等特性,能完美承接 Flink 处理后的实时数据,既满足低延迟的实时查询需求,又支持离线分析、数据回溯等场景,解决了传统存储方案 "实时写入与离线复用不可兼得" 的问题。

基于此,采用 Java 语言实现 Flink 读 Kafka 写 Paimon 的架构,本质是构建一套 "实时接入 - 实时计算 - 湖仓存储" 的端到端解决方案。Java 作为 Flink、Kafka、Paimon 生态的核心开发语言,具备完善的 API 支持、丰富的生态工具与成熟的企业级实践,能够确保架构的稳定性、可扩展性与可维护性。该方案可广泛应用于实时数据仓库构建、用户行为分析、实时监控告警、交易数据实时归档等业务场景,帮助企业打通数据流转全链路,实现数据价值的快速释放与长期复用。

二.具体实现

1.创建java工程,引入依赖

复制代码
        <dependency>
            <groupId>org.apache.paimon</groupId>
            <artifactId>paimon-flink-1.18</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.flink</groupId>
            <artifactId>flink-table-api-java-bridge</artifactId>
            <version>1.18.1</version>
        </dependency>
      <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-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>

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.转换数据流为Row格式

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

                JSONObject jsonObject = JSONObject.parseObject(value.value().toString());

                Row row = Row. withPositions(3);
                    row. setField(0, jsonObject.getString("xxxx"));
                    row. setField(1, jsonObject.getString("xxx"));
                    row. setField(2,  LocalDateTime.now());

                return row;
            }
        });

5.定义catalog

复制代码
Options catalogOptions = new Options();
        catalogOptions.set("warehouse", "hdfs://xxx.xxx");
        Catalog catalog = FlinkCatalogFactory.createPaimonCatalog(catalogOptions);

6.定义paimon 表

复制代码
org.apache.paimon.schema.Schema.Builder builder2 = org.apache.paimon.schema.Schema.newBuilder();
            builder2.column("a", org.apache.paimon.types.DataTypes.STRING());
            builder2.column("b", org.apache.paimon.types.DataTypes.STRING());
            builder2.column("c", org.apache.paimon.types.DataTypes.TIMESTAMP());
            builder2.option("write-buffer-for-append", "true");
            builder2.option("write-buffer-spillable", "false");
        org.apache.paimon.schema.Schema schema2 = builder2.build();

        catalog.createTable(Identifier.create("数据库名", "表名"), schema2, true);

        Table table = catalog.getTable(Identifier.create("数据库名", "表名"));

7.配置sink,并写入

复制代码
DataType inputType =
                DataTypes.ROW(
                        DataTypes.FIELD("a", DataTypes.STRING()),
                        DataTypes.FIELD("b", DataTypes.STRING()),
                        DataTypes.FIELD("c", DataTypes.TIMESTAMP()));
        FlinkSinkBuilder builder = new FlinkSinkBuilder(table).forRow(input, inputType);

        builder.build();
相关推荐
张np1 小时前
java基础-LinkedList(链表)
java
CoderYanger1 小时前
A.每日一题——3512. 使数组和能被 K 整除的最少操作次数
java·数据结构·算法·leetcode·职场和发展·1024程序员节
雨中飘荡的记忆1 小时前
设计模式之享元模式详解
java·设计模式·享元模式
茶杯6751 小时前
极睿iClip易视频——电商短视频智能运营的革新者
大数据·人工智能
Hello.Reader1 小时前
Flink SQL 查询(Queries)从 sqlQuery 到 executeSql
sql·flink·linq
老蒋新思维1 小时前
创客匠人峰会复盘:AI 赋能 IP 创新增长,知识变现的 4 大实战路径与跨行业案例
大数据·网络·人工智能·tcp/ip·创始人ip·创客匠人·知识变现
梓德原1 小时前
【C语言】C语言如何向系统接要存
java·c语言·算法
ManageEngineITSM1 小时前
IT 资产扫描工具与企业服务台的数字化底层价值
大数据·运维·人工智能·itsm·工单系统
WX-bisheyuange1 小时前
基于Spring Boot的流浪动物管理系统
java·spring boot·后端