实时数仓技术选型:Kafka、Flink、Spark Streaming、Paimon 核心组件介绍
做实时数仓,选型是第一步,也是最容易踩坑的一步。
我记得刚带团队做第一个实时项目时,大家争论最多的就是「用 Flink 还是 Spark Streaming」。后来踩了不少坑,才慢慢摸清楚每个组件的脾气。今天我就把这四个核心组件——Kafka、Flink、Spark Streaming、Paimon——掰开揉碎讲清楚。
一句话总结:Kafka 是管道,Flink 是引擎,Paimon 是底座,Spark Streaming 是备选。但实际落地远没这么简单。
2.1 Apache Kafka:实时数仓的「中枢神经」
Kafka 在实时数仓里扮演什么角色?说白了,它就是所有数据的「集散地」。业务日志、数据库 CDC、埋点数据……统统先往 Kafka 里塞。
我个人的选型习惯:只要实时链路超过 3 个环节,Kafka 就是必选项。为什么?因为它解耦。
- 高吞吐:单机每秒几十万条消息,我见过最大的集群撑到百万级 TPS
- 持久化:消息落盘,可以回溯。我曾经靠这个特性救了两次数据回溯的命
- 分区机制:并行消费的基础,也是保证顺序的关键
避坑指南:我曾经把 Kafka 的 retention 设得太短(1 天),结果凌晨数据管道出问题,等早上发现时数据已经没了。现在我的习惯是:核心 Topic 至少保留 3 天,配合 Compact 策略。
Kafka 在实时数仓里的典型用法:
# 生产者:模拟实时订单数据
kafka-console-producer.sh \
--broker-list kafka1:9092,kafka2:9092 \
--topic ods_order \
--property parse.key=true \
--property key.separator=:
# 消费者:Flink 或 Spark 直接消费
kafka-console-consumer.sh \
--bootstrap-server kafka1:9092 \
--topic ods_order \
--from-beginning
2.2 Apache Flink:实时计算的「主力军」
Flink 是我目前在实时数仓项目里的首选计算引擎。为什么?因为它把「实时」这件事做到了极致。
核心优势:
- 真正的流处理:每条数据来了就处理,延迟毫秒级。Spark Streaming 的微批再快也有秒级延迟
- 精确一次语义:配合 Kafka 和 Paimon,能做到端到端 Exactly-Once。这个在金融场景里是刚需
- 状态管理:内置 RocksDB 状态后端,TB 级状态不慌
我在项目中遇到过最典型的场景:实时大屏的订单金额聚合。用 Flink 的滚动窗口,10 秒刷新一次,延迟控制在 3 秒以内。
// Flink SQL:实时订单统计
CREATE TABLE orders (
order_id STRING,
user_id STRING,
amount DECIMAL(10,2),
order_time TIMESTAMP(3),
WATERMARK FOR order_time AS order_time - INTERVAL '5' SECOND
) WITH (
'connector' = 'kafka',
'topic' = 'ods_order',
'properties.bootstrap.servers' = 'kafka:9092',
'format' = 'json'
);
-- 10秒滚动窗口聚合
SELECT
TUMBLE_START(order_time, INTERVAL '10' SECOND) AS window_start,
COUNT(*) AS order_count,
SUM(amount) AS total_amount
FROM orders
GROUP BY TUMBLE(order_time, INTERVAL '10' SECOND);
注意:Flink 的状态大小会随着时间增长。我曾经有个任务跑了两个月,状态涨到 200GB,Checkpoint 一直失败。后来加了增量 Checkpoint 和状态 TTL 才解决。
2.3 Spark Streaming:批流一体的「老将」
Spark Streaming 现在用得少了,但并不是没有价值。我个人的看法是:
- 适合场景:秒级延迟可接受、已有 Spark 技术栈、批流一体需求
- 不适合场景:毫秒级延迟、复杂事件处理、超大状态
Spark Streaming 的核心是微批处理。它把流切成一个个小批次,每个批次用 Spark 引擎跑一次。延迟通常在 1-10 秒。
// Spark Structured Streaming:实时订单统计
val ordersDF = spark
.readStream
.format("kafka")
.option("kafka.bootstrap.servers", "kafka:9092")
.option("subscribe", "ods_order")
.load()
.selectExpr("CAST(value AS STRING) as json")
.select(from_json($"json", schema).as("data"))
.select("data.*")
val windowedCounts = ordersDF
.groupBy(window($"order_time", "10 seconds"))
.agg(
count("*").as("order_count"),
sum("amount").as("total_amount")
)
windowedCounts.writeStream
.outputMode("complete")
.format("console")
.start()
.awaitTermination()
我的建议:如果团队 Spark 能力强、延迟要求不高,用 Spark Streaming 没问题。但新项目我建议直接上 Flink。
2.4 Apache Paimon:湖仓一体的「新底座」
Paimon 是最近两年才火起来的。它解决了实时数仓里一个老大难问题:流式数据怎么高效入湖。
以前的做法是 Kafka -> Flink -> Hive,但 Hive 的小文件、延迟、ACID 问题让人头疼。Paimon 把 Lakehouse 的存储能力直接拉到了实时层面。
Paimon 的核心能力:
- 流批一体存储:同一份数据,既能流式写入,又能批量读取
- LSM 树结构:写入快,适合实时场景
- 增量读取:Flink 可以直接读 Paimon 的 changelog,实现实时 ETL
- 表模式演进:加列、改类型,不用重建表
-- Flink SQL 创建 Paimon 表
CREATE CATALOG paimon WITH (
'type' = 'paimon',
'warehouse' = 'hdfs://namenode:8020/warehouse'
);
CREATE TABLE paimon.ods.orders (
order_id STRING,
user_id STRING,
amount DECIMAL(10,2),
order_time TIMESTAMP(3),
dt STRING,
PRIMARY KEY (order_id) NOT ENFORCED
) PARTITIONED BY (dt)
WITH (
'bucket' = '4',
'changelog-producer' = 'input',
'snapshot.time-retained' = '3d'
);
实战经验:我最近一个项目用 Paimon 替换了 Hive,实时链路从 Kafka -> Flink -> Hive 变成了 Kafka -> Flink -> Paimon。延迟从分钟级降到了秒级,小文件问题也自动解决了。
2.5 技术选型对比
这四个组件怎么搭?我整理了一张对比表:
| 维度 | Kafka | Flink | Spark Streaming | Paimon |
|---|---|---|---|---|
| 定位 | 消息管道 | 流计算引擎 | 微批计算引擎 | 湖仓存储 |
| 延迟 | 毫秒级 | 毫秒级 | 秒级 | 秒级(写入) |
| 状态管理 | 无 | 强(RocksDB) | 弱(依赖外部) | 内置 LSM |
| 精确一次 | 支持 | 支持 | 支持 | 支持 |
| 适用场景 | 数据中转 | 实时 ETL、大屏 | 批流一体 | 实时入湖 |
2.6 整体架构图
下面这张图是我现在做实时数仓的标准架构。你想想看,数据从产生到落地,每一步都有对应的组件:
我的选型建议:新项目直接上 Kafka + Flink + Paimon 三件套。Spark Streaming 留着做批流一体的补充。这套组合我用了两年,稳定性很高。
2.7 选型决策流程
最后,我分享一个选型决策的思路。遇到新项目时,我会问自己三个问题:
- 延迟要求多少?毫秒级 → Flink;秒级 → Spark Streaming 也行
- 数据要入湖吗?要 → Paimon;不要 → Kafka 直接消费
- 团队熟悉什么?Java/ Scala 多 → Flink;Python 多 → Spark