一.背景
在数字化转型加速的当下,企业业务场景日益复杂,数据呈现出 高并发、低延迟、多源异构 的核心特征。日志采集、交易流水、用户行为等实时数据源源不断产生,这类数据不仅需要被快速接收、处理,更需要长期存储以便后续离线分析、数据回溯与合规审计,形成 “实时处理 + 离线复用” 的完整数据闭环。
传统数据处理架构中,实时数据常通过消息队列(如 Kafka)暂存,但 Kafka 仅适用于流式数据的临时存储与传输,不支持高效的离线查询、数据更新与分层管理;而传统数据仓库(如 Hive)虽能满足离线分析需求,却难以应对实时数据的低延迟处理诉求,导致 “实时处理” 与 “长期存储” 脱节,无法兼顾业务对数据时效性和复用性的双重要求。
在此背景下,各类组件的协同架构成为解决该痛点的关键:
- Kafka 作为实时数据接入层:凭借高吞吐、低延迟、高容错的特性,Kafka 已成为企业实时数据流转的核心枢纽,承担着日志、交易、传感器等实时数据流的接收与分发任务,是实时数据处理的 “数据源头”;
- Flink 作为实时计算引擎:Flink 具备强大的流批一体处理能力,支持 Exactly-Once 语义、复杂事件处理(CEP)、状态管理等核心特性,能够高效消费 Kafka 中的实时数据流,完成数据清洗、转换、聚合、关联等计算逻辑,是连接 “数据源头” 与 “存储终端” 的核心计算桥梁;
- 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();
2211

被折叠的 条评论
为什么被折叠?



