构建 Flink → Kafka → ClickHouse → MinIO 的完整数据链路,是现代实时数仓(Real-time Data Warehouse)和湖仓一体(Lakehouse)架构的经典范式。它实现了从实时数据采集、流式处理、高性能分析到低成本归档的全链路闭环。
本篇将带你一步步实践这条完整的数据流水线,涵盖各组件的配置、集成与最佳实践。
🎯 一、目标架构
[Flink] → 实时流处理(ETL、聚合)
│
↓
[Kafka] → 消息缓冲(解耦、削峰)
│
↓
[ClickHouse] → 实时分析(热数据存储)
│
↓
[MinIO] ← 数据归档(冷数据存储)
✅ 实现效果:
- 实时摄入:秒级延迟
- 高性能查询:ClickHouse 支持复杂聚合
- 自动归档:TTL + S3 写入 MinIO
- 成本优化:热数据快,冷数据省
🧰 二、环境准备
| 组件 | 版本建议 | 部署方式 |
|---|---|---|
| Apache Flink | ≥ v1.17 | Standalone / Kubernetes |
| Apache Kafka | ≥ v3.0 | 集群部署 |
| ClickHouse | ≥ v22.8 | 集群或单机 |
| MinIO | ≥ RELEASE.2023 | Docker / Binary |
| 网络 | 所有组件互通 | 建议同内网 |
✅ 假设各组件已部署并可访问。
📦 三、步骤 1:准备数据源(模拟原始数据)
假设我们处理的是用户行为日志,原始格式如下:
{
"user_id": 1001,
"event_type": "pageview",
"page_url": "/home",
"device_type": "mobile",
"event_time": "2024-04-01 10:00:00"
}
🔗 四、步骤 2:Flink → Kafka(实时 ETL)
使用 Flink 从外部源(如文件、数据库)读取数据,进行清洗、转换后写入 Kafka。
1. Flink 作业(Java/Scala 或 SQL)
// 读取数据源(示例:Kafka Source / File Source)
DataStream<String> source = env.addSource(new FlinkKafkaConsumer<>("raw-topic", ...));
// 解析 JSON 并转换
DataStream<UserBehavior> cleaned = source.map(json -> {
// 解析 JSON,过滤脏数据,补全字段
return parseJsonToUserBehavior(json);
});
// 写入 Kafka
cleaned.addSink(new FlinkKafkaProducer<>(
"user-behavior-topic",
new SimpleStringSchema(),
kafkaProps
));
2. Kafka Producer 配置
bootstrap.servers=kafka1:9092,kafka2:9092
key.serializer=org.apache.kafka.common.serialization.StringSerializer
value.serializer=org.apache.kafka.common.serialization.StringSerializer
✅ 输出到 Kafka 主题:
user-behavior-topic
🚀 五、步骤 3:Kafka → ClickHouse(实时分析)
通过 ClickHouse 的 Kafka Engine 表 + Materialized View 实现实时摄入。
1. 创建 Kafka 引擎表
CREATE TABLE kafka_user_behavior (
user_id UInt32,
event_type String,
page_url String,
device_type String,
event_time DateTime
) ENGINE = Kafka
SETTINGS
kafka_broker_list = 'kafka1:9092',
kafka_topic_list = 'user-behavior-topic',
kafka_group_name = 'ch-consumer-group',
kafka_format = 'JSONEachRow';
2. 创建本地目标表(热数据)
CREATE TABLE user_behavior_local (
user_id UInt32,
event_type String,
page_url String,
device_type String,
event_date Date DEFAULT toDate(event_time),
event_time DateTime
) ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/user_behavior_local',
'{replica}'
)
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, event_type, user_id)
TTL event_date + INTERVAL 7 DAY TO VOLUME 'minio_volume' -- 7天后归档到 MinIO
SETTINGS
storage_policy = 'tiered_with_minio';
3. 创建物化视图(自动写入)
CREATE MATERIALIZED VIEW mv_kafka_to_local
TO user_behavior_local
AS SELECT
user_id,
event_type,
page_url,
device_type,
event_time
FROM kafka_user_behavior;
✅ 效果:Kafka 消息自动写入 ClickHouse,支持实时查询。
💾 六、步骤 4:ClickHouse → MinIO(自动归档)
1. 配置 MinIO 存储卷(在 config.xml 中)
<storage_configuration>
<disks>
<default> <path>/var/lib/clickhouse/</path> </default>
<minio>
<type>s3</type>
<endpoint>http://minio:9000/clickhouse-archive/</endpoint>
<access_key_id>admin</access_key_id>
<secret_access_key>minioadmin</secret_access_key>
</minio>
</disks>
<policies>
<tiered_with_minio>
<volumes>
<hot><disk>default</disk></hot>
<cold><disk>minio</disk></cold>
</volumes>
</tiered_with_minio>
</policies>
</storage_configuration>
2. TTL 自动迁移
TTL event_date + INTERVAL 7 DAY TO VOLUME 'cold'
- 7 天后数据从本地自动迁移到 MinIO
- 存储格式为 ClickHouse 内部格式(可读)
3. (可选)物化视图直接写入 MinIO(Parquet 格式)
CREATE MATERIALIZED VIEW mv_user_behavior_to_minio
TO default.none
AS
INSERT INTO FUNCTION
s3(
'http://minio:9000/clickhouse-archive/user_behavior/{_partition_id}.parquet',
'admin',
'minioadmin',
'Parquet'
)
SELECT
user_id, event_type, page_url, device_type, event_time
FROM user_behavior_local;
✅ 优势:生成标准 Parquet 文件,可被 Trino、Spark 读取
📊 七、数据查询与分析
1. 查询热数据(最近 7 天)
SELECT
event_type,
COUNT(*) AS cnt,
COUNT(DISTINCT user_id) AS uv
FROM user_behavior_local
WHERE event_date >= today() - INTERVAL 7 DAY
GROUP BY event_type;
2. 查询归档数据(MinIO)
SELECT
event_type,
COUNT(*) AS cnt
FROM s3(
'http://minio:9000/clickhouse-archive/user_behavior/*.parquet',
'admin',
'minioadmin',
'Parquet'
)
WHERE toDate(event_time) BETWEEN '2024-01-01' AND '2024-03-31'
GROUP BY event_type;
3. 联合查询(热 + 冷)
SELECT
event_type,
SUM(cnt) AS total
FROM (
SELECT event_type, COUNT(*) AS cnt FROM user_behavior_local GROUP BY event_type
UNION ALL
SELECT event_type, COUNT(*) AS cnt FROM user_behavior_archive GROUP BY event_type
)
GROUP BY event_type;
📈 八、性能优化建议
| 组件 | 优化建议 |
|---|---|
| Flink | 使用 KeyedStream 聚合,开启 Checkpoint |
| Kafka | 分区数 ≥ Flink 并行度,压缩 snappy |
| ClickHouse | 批量写入,合理设计 ORDER BY |
| MinIO | 使用 SSD,多节点部署 |
| 网络 | ClickHouse 与 MinIO 同内网,低延迟 |
🔍 九、监控与可观测性
| 工具 | 用途 |
|---|---|
| Flink Web UI | 监控作业延迟、吞吐 |
| Kafka Manager / Redpanda Console | 查看 Topic 消费情况 |
| ClickHouse system tables | system.kafka_consumers, system.parts |
| Prometheus + Grafana | 全链路指标监控 |
| MinIO Console | 查看存储用量、访问日志 |
🎯 十、总结:Flink → Kafka → ClickHouse → MinIO 的核心价值
| 阶段 | 技术 | 价值 |
|---|---|---|
| 实时处理 | Flink | 流式 ETL、状态管理 |
| 消息缓冲 | Kafka | 解耦、高吞吐、可靠 |
| 实时分析 | ClickHouse | 秒级聚合查询 |
| 低成本归档 | MinIO | 长期存储,开放格式 |
🎯 这是现代数据架构的“黄金链路”:
- 实时性:端到端秒级延迟
- 可靠性:Kafka 保证不丢
- 可扩展性:各组件均可水平扩展
- 成本效益:热冷分层,存储优化
1029

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



