2026-04-13 · architecture
【系统架构设计百科】数据湖与数据仓库:分析架构的演进路线
Lambda、Kappa、Lakehouse 三种架构的本质区别和适用场景是什么?本文深入 Delta Lake 和 Apache Iceberg 的设计原理,分析流批一体的工程挑战,并提供数据质量保证的架构方案。























当一个电商平台的订单数据从每天 500 万条增长到每天 5 亿条,当业务部门要求从”T+1 看报表”变成”实时看大盘”,当数据团队同时维护一套 Hadoop 批处理管线和一套 Kafka + Storm 实时管线并为两条链路的数据不一致焦头烂额时——数据密集型架构(Data-Intensive Architecture)的核心矛盾便暴露无遗。过去十年,行业经历了从 MapReduce 到 Lambda 架构(Lambda Architecture),再到 Kappa 架构(Kappa Architecture),最终走向批流一体(Unified Batch and Streaming)与湖仓一体(Lakehouse)的完整演进路径。本文将沿着这条主线,拆解每一步演进背后的技术动因与工程取舍。
2004 年 Google 发表 MapReduce 论文,Hadoop 生态随后在工业界普及。这一阶段的数据处理模式非常直接:
这套架构的优点是简单、可靠、吞吐量大,但致命弱点也很明显——延迟高。一次完整的批处理管线从数据采集到结果可用,通常需要数小时甚至隔天(T+1)。对于实时风控、实时推荐、实时监控等场景,T+1 完全不可接受。
为了填补延迟空白,Storm、Samza 等流处理(Stream Processing)框架应运而生。它们的核心思想是:数据到达即处理,延迟可降至秒级甚至毫秒级。
然而早期流处理框架面临两个根本问题:
于是,一个折中方案诞生了——Lambda 架构。
下面用一个简化的时间线梳理关键节点:
| 年份 | 里程碑 | 核心特征 |
|---|---|---|
| 2004 | Google MapReduce 论文 | 大规模批处理 |
| 2011 | Apache Storm 开源 | 实时流处理 |
| 2012 | Nathan Marz 提出 Lambda 架构 | 批处理 + 流处理双轨制 |
| 2014 | Jay Kreps 提出 Kappa 架构 | 以流为本的统一模型 |
| 2016 | Apache Flink 1.0 发布 | 事件驱动(Event-Driven)、精确一次语义 |
| 2018 | Spark Structured Streaming GA | 微批 + 连续处理模式 |
| 2019 | Delta Lake 开源、Apache Iceberg 进入孵化 | 数据湖上的 ACID |
| 2020 | Databricks 提出 Lakehouse 概念 | 湖仓一体 |
| 2023 | Apache Paimon 进入孵化 | 面向流的 Table Format |
Lambda 架构由 Nathan Marz 在其著作《Big Data: Principles and Best Practices of Scalable Realtime Data Systems》中系统阐述。其核心思想是将数据处理分为三层:
graph TD
A[数据源] -->|全量写入| B[批处理层<br/>Hadoop / Spark]
A -->|实时流入| C[速度层<br/>Storm / Flink]
B -->|定期生成| D[批视图<br/>Batch View]
C -->|持续更新| E[实时视图<br/>Real-time View]
D --> F[服务层<br/>Serving Layer]
E --> F
F --> G[查询接口]
在大规模工程实践中,Lambda 架构暴露出三个致命问题:
问题一:双倍开发与维护成本。 同一套业务逻辑需要用两种完全不同的编程模型实现——批处理通常用 SQL 或 Spark,流处理用 Java / Scala 的流式 API。两套代码的同步维护是噩梦。
// 批处理:Spark SQL 统计每小时订单量
spark.sql("""
SELECT hour(order_time) AS hr, COUNT(*) AS cnt
FROM orders
WHERE dt = '2026-04-12'
GROUP BY hour(order_time)
""");
// 流处理:Storm Bolt 实现相同逻辑
public class OrderCountBolt extends BaseRichBolt {
private Map<Integer, Long> hourlyCount = new HashMap<>();
@Override
public void execute(Tuple tuple) {
int hour = tuple.getIntegerByField("hour");
hourlyCount.merge(hour, 1L, Long::sum);
// 需要手动处理窗口、状态、容错...
}
}两段代码实现的是完全相同的业务逻辑,但编程模型、测试方式、部署运维流程完全不同。
问题二:数据一致性难以保证。 批视图与实时视图在合并时存在时间窗口的重叠或空白,可能导致数据重复计算或漏算。服务层的 merge 逻辑往往需要大量 ad-hoc 的修补代码。
问题三:运维复杂度高。 需要同时运维 HDFS 集群、批处理调度器(Oozie / Airflow)、流处理集群、服务层数据库,任何一个环节故障都可能导致数据链路断裂。
正是这些痛点,催生了 Kappa 架构。
2014 年,LinkedIn 的 Jay Kreps(Apache Kafka 的作者)在一篇博客文章中提出了 Kappa 架构。其核心思想极其简洁:
既然所有数据都可以看作事件流(Event Stream),为什么不用一套流处理引擎同时处理实时数据和历史数据?
Kappa 架构去掉了 Lambda 的批处理层,只保留一条流处理管线:
graph LR
A[数据源] --> B[Kafka<br/>持久化消息队列]
B --> C[流处理引擎<br/>Flink / Kafka Streams]
C --> D[结果存储<br/>实时视图]
D --> E[查询接口]
B -->|回拨 Offset| C
Kappa 架构并非万能。它能成立依赖于两个技术前提:
Kappa 架构虽然简化了架构,但在实践中仍存在局限:
因此,现代数据架构的最终方向是批流一体——不是”只用流”或”只用批”,而是用同一套引擎、同一套代码、同一套语义来处理批数据和流数据。Flink 和 Spark 在这个方向上走出了两条截然不同的技术路线。
这是数据密集型架构中最核心的技术选型问题之一。两者都宣称支持批流一体,但底层架构理念截然不同。
Flink:流优先(Stream-First)。 Flink 将一切数据视为无界流(Unbounded Stream),批处理只是流处理的特例——有界流(Bounded Stream)。其核心执行引擎是基于事件驱动的流式引擎,天然支持低延迟处理。
Spark Structured Streaming:批优先(Batch-First)。 Spark 的核心引擎是批处理引擎,Structured Streaming 在其上构建了一个微批处理(Micro-Batch)模型——将流数据切分为一个个小的批次(通常 100ms ~ 数秒),然后用 Spark 的批处理引擎逐批执行。
精确一次(Exactly-Once)语义是数据一致性的基石。两者的实现路径不同:
Flink 的检查点机制(Checkpointing):
Flink 使用 Chandy-Lamport 分布式快照算法的变体。其工作流程如下:
// Flink 检查点配置
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.enableCheckpointing(60000); // 每 60 秒做一次检查点
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(30000);
env.getCheckpointConfig().setCheckpointTimeout(120000);
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
// 配合 Kafka Source 的精确一次消费
KafkaSource<String> source = KafkaSource.<String>builder()
.setBootstrapServers("kafka:9092")
.setTopics("orders")
.setGroupId("order-processor")
.setStartingOffsets(OffsetsInitializer.committedOffsets())
.setValueOnlyDeserializer(new SimpleStringSchema())
.build();
DataStream<String> stream = env.fromSource(
source,
WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(5)),
"Kafka Source"
);Spark Structured Streaming 的 WAL 与幂等写入:
Spark 通过预写日志(Write-Ahead Log, WAL)记录每个微批次消费的 Offset 范围,结合幂等写入(Idempotent Write)或两阶段提交(Two-Phase Commit)实现端到端精确一次。
# Spark Structured Streaming 精确一次配置
df = spark \
.readStream \
.format("kafka") \
.option("kafka.bootstrap.servers", "kafka:9092") \
.option("subscribe", "orders") \
.option("startingOffsets", "earliest") \
.load()
query = df \
.selectExpr("CAST(value AS STRING)") \
.writeStream \
.outputMode("append") \
.format("delta") \
.option("checkpointLocation", "/checkpoint/orders") \
.trigger(processingTime="10 seconds") \
.start("/data/orders")状态管理(State Management)是流处理中最具挑战性的问题。窗口聚合、去重、模式匹配等操作都需要维护跨事件的状态。
Flink 的状态后端(State Backend):
Flink 提供三种状态后端:
| 状态后端 | 存储位置 | 适用场景 | 状态大小上限 |
|---|---|---|---|
| HashMapStateBackend | JVM 堆内存 | 状态较小、低延迟 | 受 JVM 堆大小限制 |
| EmbeddedRocksDBStateBackend | 本地磁盘(RocksDB) | 状态极大 | 受磁盘大小限制 |
| ForStStateBackend | 本地磁盘(ForSt) | 状态极大、云原生优化 | 受磁盘大小限制 |
RocksDB 状态后端是生产环境的主流选择。它将状态存储在本地 SSD 上的 RocksDB 实例中,支持增量检查点(Incremental Checkpoint),只上传自上次检查点以来发生变化的 SST 文件,大幅降低检查点开销。
// 配置 RocksDB 状态后端与增量检查点
env.setStateBackend(new EmbeddedRocksDBStateBackend(true)); // true 表示启用增量检查点
env.getCheckpointConfig().setCheckpointStorage("s3://my-bucket/flink-checkpoints");Spark 的状态管理:
Spark Structured Streaming 的状态管理相对简单,状态存储在 HDFS/S3 上的检查点目录中。每个微批次结束时,状态快照写入检查点。这种方式的优点是简单可靠,但缺点是状态更新的粒度较粗——如果某个微批次处理时间过长,状态写入会成为瓶颈。
| 维度 | Apache Flink | Spark Structured Streaming |
|---|---|---|
| 架构理念 | 流优先,批是有界流 | 批优先,流是连续微批 |
| 延迟 | 毫秒级(真正的事件驱动) | 秒级至分钟级(微批间隔) |
| 精确一次 | 分布式快照(Chandy-Lamport) | WAL + 幂等写入 |
| 状态管理 | RocksDB / 堆内存,支持增量检查点 | HDFS 检查点,全量快照 |
| 事件时间处理 | 原生 Watermark 机制,灵活度高 | 支持 Watermark,但配置灵活度较低 |
| SQL 支持 | Flink SQL,持续查询(Continuous Query) | Spark SQL,微批查询 |
| 生态成熟度 | CDC(Change Data Capture)生态完善 | 与 MLlib、GraphX 等批处理生态集成好 |
| 运维复杂度 | 较高(TaskManager、JobManager 管理) | 中等(复用 Spark 集群) |
| 社区活跃度 | 阿里巴巴主导,中国社区活跃 | Databricks 主导,全球社区广泛 |
| 典型用户 | 阿里巴巴、字节跳动、Uber | Netflix、Apple、Databricks 客户 |
在 Lakehouse 概念出现之前,企业的数据存储通常分为两个系统:
数据湖(Data Lake): 以 HDFS 或对象存储(S3、OSS)为基础,存储原始的、未经结构化处理的数据(Parquet、ORC、JSON、日志等)。优点是成本低、灵活,缺点是缺乏事务支持、数据质量差、查询性能低。
数据仓库(Data Warehouse): 以 Snowflake、Redshift、BigQuery 等为代表,提供高性能的 SQL 查询、ACID 事务、Schema 管理。优点是查询快、数据质量高,缺点是存储成本高、数据需要从数据湖 ETL 过来(引入额外延迟和复杂度)。
这种”两套系统”的架构带来了与 Lambda 架构类似的问题——数据冗余、一致性难保证、运维复杂。
2020 年,Databricks 在论文《Lakehouse: A New Generation of Open Platforms that Unify Data Warehousing and Advanced Analytics》中正式提出 Lakehouse 概念。其核心思想是:
在数据湖的低成本存储之上,叠加数据仓库的管理能力(ACID 事务、Schema 管理、索引优化),实现一套系统同时满足 BI 分析(Business Intelligence)和机器学习(Machine Learning)的需求。
graph TB
subgraph Lakehouse 架构
A[对象存储<br/>S3 / HDFS / OSS] --> B[Table Format<br/>Delta Lake / Iceberg / Hudi]
B --> C[计算引擎<br/>Spark / Flink / Trino / Presto]
C --> D1[BI 分析]
C --> D2[机器学习]
C --> D3[实时数仓]
end
subgraph 传统双系统架构
E[数据湖<br/>S3 / HDFS] -->|ETL| F[数据仓库<br/>Redshift / Snowflake]
E --> G[ML 引擎<br/>TensorFlow / PyTorch]
F --> H[BI 工具]
end
Lakehouse 之所以能在数据湖上实现数据仓库级别的管理能力,核心在于 Table Format 层。Table Format 在原始数据文件(Parquet/ORC)之上引入了一层元数据管理,提供以下关键能力:
Table Format 是 Lakehouse 架构的核心支撑层。当前行业存在三个主要的开源 Table Format,各有侧重。
Delta Lake 由 Databricks 开源,与 Spark 生态深度绑定。
核心机制: Delta Lake
使用事务日志(Transaction Log)——_delta_log
目录下的 JSON
文件——记录每次对表的操作(添加文件、删除文件、修改元数据等)。每次写操作生成一个新的
JSON 文件(如 000001.json),每 10 个 JSON
文件自动合并为一个 Checkpoint 文件(Parquet
格式)以加速元数据读取。
-- Delta Lake 时间旅行:查询 1 小时前的数据
SELECT * FROM orders VERSION AS OF 42;
-- 或者按时间戳查询
SELECT * FROM orders TIMESTAMP AS OF '2026-04-12 14:00:00';
-- Delta Lake MERGE(Upsert)操作
MERGE INTO target_table AS t
USING source_table AS s
ON t.order_id = s.order_id
WHEN MATCHED THEN
UPDATE SET t.status = s.status, t.update_time = s.update_time
WHEN NOT MATCHED THEN
INSERT (order_id, user_id, amount, status, update_time)
VALUES (s.order_id, s.user_id, s.amount, s.status, s.update_time);Apache Iceberg 由 Netflix 开源,设计目标是引擎无关(Engine-Agnostic)。
核心机制: Iceberg 使用分层的元数据结构:
这种分层设计的关键优势是分区演化。传统 Hive 分区方案一旦确定便无法更改(如从按天分区改为按小时分区需要重写所有数据),而 Iceberg 的分区信息存储在 Manifest 级别,可以在不重写数据的前提下修改分区策略。
-- Iceberg 分区演化:从按天分区改为按小时分区
ALTER TABLE orders WRITE ORDERED BY (order_time);
ALTER TABLE orders SET PARTITION SPEC (
hours(order_time)
);
-- 后续写入的数据使用新的分区策略,旧数据保持不变
-- Iceberg 快照查询
SELECT * FROM orders FOR SYSTEM_TIME AS OF TIMESTAMP '2026-04-12 14:00:00';
-- Iceberg 增量读取(用于构建流式管线)
SELECT * FROM orders
WHERE snapshot_id BETWEEN 1001 AND 1005;Apache Hudi(Hadoop Upserts Deletes and Incrementals)由 Uber 开源,最初的设计目标是解决数据湖上的 Upsert 问题。Hudi 提供两种存储类型:
| 维度 | Delta Lake | Apache Iceberg | Apache Hudi |
|---|---|---|---|
| 开源方 | Databricks | Netflix / Apple | Uber |
| 引擎绑定 | 与 Spark 深度绑定 | 引擎无关 | 主要支持 Spark |
| 元数据管理 | 事务日志(JSON + Parquet Checkpoint) | 分层元数据(Catalog → Manifest) | 时间线(Timeline)机制 |
| 分区演化 | 不支持(需重写数据) | 原生支持 | 部分支持 |
| Schema 演化 | 支持(添加列、重命名列) | 完整支持(基于 ID 的 Schema) | 支持(添加列) |
| 时间旅行 | 支持 | 支持 | 支持 |
| 流式读写 | 支持(Spark Structured Streaming) | 支持(Flink Iceberg Connector) | 原生支持(核心设计目标) |
| 并发控制 | 乐观并发(Optimistic Concurrency) | 乐观并发 + 序列化隔离 | 基于时间线的 MVCC |
| 社区与生态 | Databricks 主导,商业化成熟 | Apache 基金会,厂商中立 | Uber 主导,Onehouse 商业化 |
传统离线数仓遵循经典的分层模型:ODS → DWD → DWS → ADS。实时数仓的分层模型与之对应,但每一层都需要实时更新:
| 层次 | 离线数仓 | 实时数仓 | 技术选型 |
|---|---|---|---|
| ODS(Operational Data Store) | HDFS 原始文件 | Kafka Topic | Kafka / Pulsar |
| DWD(Data Warehouse Detail) | Hive 明细表 | Flink 清洗后写入 Kafka/Iceberg | Flink SQL |
| DWS(Data Warehouse Summary) | Hive 汇总表 | Flink 聚合后写入 OLAP 引擎 | Flink SQL + StarRocks |
| ADS(Application Data Store) | MySQL 结果表 | OLAP 引擎直接服务查询 | StarRocks / ClickHouse |
下面给出一个生产级实时数仓架构的完整技术栈:
数据源(MySQL / MongoDB / 日志)
│
▼ CDC(Debezium / Flink CDC)
│
Kafka(ODS 层:原始事件流)
│
▼ Flink SQL(数据清洗、维表关联)
│
Iceberg / Kafka(DWD 层:明细事实表)
│
▼ Flink SQL(窗口聚合、指标计算)
│
StarRocks / ClickHouse(DWS + ADS 层:汇总与服务)
│
▼
BI 工具 / 数据 API / 实时大屏
Flink CDC(Change Data Capture)是打通实时数仓全链路的关键组件。它可以直接读取 MySQL 的 Binlog、PostgreSQL 的 WAL、MongoDB 的 Oplog,将数据变更事件转化为 Flink 的数据流。
-- Flink SQL:创建 MySQL CDC Source 表
CREATE TABLE orders_source (
order_id BIGINT,
user_id BIGINT,
product_id BIGINT,
amount DECIMAL(10, 2),
status STRING,
order_time TIMESTAMP(3),
update_time TIMESTAMP(3),
PRIMARY KEY (order_id) NOT ENFORCED
) WITH (
'connector' = 'mysql-cdc',
'hostname' = 'mysql-host',
'port' = '3306',
'username' = 'flink_reader',
'password' = '${secret}',
'database-name' = 'ecommerce',
'table-name' = 'orders',
'scan.startup.mode' = 'initial'
);
-- Flink SQL:创建 Iceberg Sink 表(DWD 层)
CREATE TABLE dwd_orders (
order_id BIGINT,
user_id BIGINT,
product_id BIGINT,
amount DECIMAL(10, 2),
status STRING,
order_time TIMESTAMP(3),
update_time TIMESTAMP(3),
user_name STRING,
user_level STRING,
PRIMARY KEY (order_id) NOT ENFORCED
) WITH (
'connector' = 'iceberg',
'catalog-name' = 'iceberg_catalog',
'catalog-type' = 'hive',
'warehouse' = 's3://data-lake/iceberg',
'format-version' = '2',
'write.upsert.enabled' = 'true'
);
-- Flink SQL:维表关联,将订单与用户信息打宽
INSERT INTO dwd_orders
SELECT
o.order_id,
o.user_id,
o.product_id,
o.amount,
o.status,
o.order_time,
o.update_time,
u.user_name,
u.user_level
FROM orders_source AS o
LEFT JOIN users_dim FOR SYSTEM_TIME AS OF o.proctime AS u
ON o.user_id = u.user_id;实时数仓的核心技术挑战之一是增量计算(Incremental Computation)。传统批处理每次全量重算所有数据,而实时数仓需要在新数据到达时只计算增量部分。
物化视图(Materialized View) 是增量计算的典型载体。以 StarRocks 为例:
-- StarRocks:创建异步物化视图实现增量聚合
CREATE MATERIALIZED VIEW mv_hourly_revenue
REFRESH ASYNC EVERY (INTERVAL 1 MINUTE)
AS
SELECT
DATE_TRUNC('hour', order_time) AS hour_key,
product_category,
COUNT(*) AS order_count,
SUM(amount) AS total_revenue,
AVG(amount) AS avg_order_amount
FROM dwd_orders
WHERE status = 'completed'
GROUP BY
DATE_TRUNC('hour', order_time),
product_category;
-- 查询时自动路由到物化视图
SELECT * FROM mv_hourly_revenue
WHERE hour_key >= '2026-04-12 10:00:00'
ORDER BY total_revenue DESC;Flink 的持续查询(Continuous Query)也是增量计算的一种实现。Flink SQL 中的 GROUP BY 聚合本质上维护了一个持续更新的物化视图:
-- Flink SQL:持续计算每分钟每品类的订单量和 GMV
CREATE TABLE dws_realtime_metrics (
window_start TIMESTAMP(3),
product_category STRING,
order_count BIGINT,
gmv DECIMAL(18, 2),
PRIMARY KEY (window_start, product_category) NOT ENFORCED
) WITH (
'connector' = 'starrocks',
'jdbc-url' = 'jdbc:mysql://starrocks:9030',
'load-url' = 'starrocks:8030',
'database-name' = 'realtime_dw',
'table-name' = 'dws_realtime_metrics',
'sink.properties.format' = 'json',
'sink.buffer-flush.interval-ms' = '5000'
);
INSERT INTO dws_realtime_metrics
SELECT
TUMBLE_START(order_time, INTERVAL '1' MINUTE) AS window_start,
product_category,
COUNT(*) AS order_count,
SUM(amount) AS gmv
FROM dwd_orders
GROUP BY
TUMBLE(order_time, INTERVAL '1' MINUTE),
product_category;背景: 某头部电商平台日均订单量 3 亿笔,峰值 QPS(Queries Per Second)达 50 万。原有架构为经典 Lambda 架构:离线链路使用 Spark + Hive(T+1),实时链路使用 Storm + HBase。两条链路的数据不一致率约 3%~5%,且实时链路在大促期间经常出现反压(Backpressure)导致数据延迟飙升至分钟级。
改造目标:
技术方案:
| 组件 | 改造前 | 改造后 |
|---|---|---|
| 消息队列 | Kafka 0.10 | Kafka 3.x |
| 流处理引擎 | Storm(实时) + Spark(离线) | Flink 1.18(统一) |
| 数据湖存储 | HDFS + Hive | S3 + Apache Iceberg |
| OLAP 引擎 | Druid | StarRocks |
| CDC 工具 | 自研 Binlog 解析 | Flink CDC 3.0 |
| 调度系统 | Oozie | 取消(Flink 常驻任务) |
改造效果:
| 指标 | 改造前 | 改造后 | 改善幅度 |
|---|---|---|---|
| 端到端延迟 | 1~5 分钟 | 3~8 秒 | 降低 97% |
| 批流数据一致率 | 95%~97% | 99.99% | 显著提升 |
| 存储成本(月均) | 280 万元 | 168 万元 | 降低 40% |
| ETL 代码行数 | 12 万行(两套) | 4.5 万行(一套) | 减少 62% |
| 故障恢复时间(RTO) | 30~60 分钟 | 2~5 分钟 | 降低 90% |
关键技术决策:
实时数仓虽然在延迟和一致性上有巨大优势,但也引入了新的挑战:
挑战一:数据回溯(Data Backfill)。 当业务逻辑变更需要重算历史数据时,纯流式架构需要从 Kafka 回拨 Offset 重消费,但 Kafka 通常只保留有限天数的数据。解决方案是使用 Iceberg 的快照读取能力从数据湖回溯:
-- 使用 Flink 读取 Iceberg 历史快照进行回溯计算
CREATE TABLE orders_backfill (
order_id BIGINT,
user_id BIGINT,
amount DECIMAL(10, 2),
order_time TIMESTAMP(3)
) WITH (
'connector' = 'iceberg',
'catalog-name' = 'iceberg_catalog',
'catalog-type' = 'hive',
'warehouse' = 's3://data-lake/iceberg',
'streaming' = 'false',
'snapshot-id' = '3821550127947089987'
);挑战二:小文件问题(Small File Problem)。 流式写入会产生大量小文件,严重影响读取性能和存储效率。Iceberg 提供了自动合并(Auto-Compaction)功能:
-- Iceberg 小文件合并
CALL iceberg_catalog.system.rewrite_data_files(
table => 'db.dwd_orders',
strategy => 'sort',
sort_order => 'order_time ASC',
options => map(
'target-file-size-bytes', '268435456',
'min-file-size-bytes', '67108864',
'max-file-size-bytes', '536870912'
)
);挑战三:精确一次的端到端保障。 从 Source 到 Sink 的精确一次语义需要整条链路的配合。以 Flink + Kafka + Iceberg 链路为例,需要同时满足:
数据质量(Data Quality)在实时场景下更难保障,因为数据一旦流过便不可回头。常见的实时数据质量检查手段包括:
-- Flink SQL:实时数据质量监控
-- 检测订单金额异常(金额为负或超过阈值)
SELECT
TUMBLE_START(order_time, INTERVAL '5' MINUTE) AS check_window,
COUNT(*) AS total_orders,
SUM(CASE WHEN amount <= 0 THEN 1 ELSE 0 END) AS negative_amount_count,
SUM(CASE WHEN amount > 100000 THEN 1 ELSE 0 END) AS high_amount_count,
SUM(CASE WHEN user_id IS NULL THEN 1 ELSE 0 END) AS null_user_count
FROM orders_source
GROUP BY TUMBLE(order_time, INTERVAL '5' MINUTE)
HAVING
SUM(CASE WHEN amount <= 0 THEN 1 ELSE 0 END) > 10
OR SUM(CASE WHEN user_id IS NULL THEN 1 ELSE 0 END) > 100;
-- 异常数据写入告警队列数据密集型架构的演进历程可以用一句话概括:从分裂走向统一。
| 演进阶段 | 核心思想 | 解决的问题 | 引入的新问题 |
|---|---|---|---|
| 纯批处理 | 全量定期计算 | 大规模数据处理 | 延迟高(T+1) |
| Lambda 架构 | 批流双轨制 | 兼顾延迟和准确性 | 双倍开发成本、数据不一致 |
| Kappa 架构 | 以流为本 | 统一处理链路 | 历史回溯困难、复杂查询低效 |
| 批流一体 | 同一引擎、同一代码 | 消除批流割裂 | 引擎选型复杂 |
| Lakehouse | 湖仓融合 | 消除数据湖与仓库割裂 | Table Format 选型、生态碎片化 |
选择哪条路线,取决于业务的具体约束:
没有万能的架构,只有在具体约束下的最优解。理解每一步演进背后的技术动因和工程取舍,比记住某个框架的 API 更为重要。
上一篇:系统架构设计百科|WebAssembly 架构(待写)
下一篇:系统架构设计百科|多租户架构(待写)
把当前热点继续串成多页阅读,而不是停在单篇消费。
2026-04-13 · architecture
Lambda、Kappa、Lakehouse 三种架构的本质区别和适用场景是什么?本文深入 Delta Lake 和 Apache Iceberg 的设计原理,分析流批一体的工程挑战,并提供数据质量保证的架构方案。
2026-04-22 · architecture / fintech
从金融本质、分层架构到文件格式、匹配算法、差错处理与调账流程,系统讲解对账系统的工程落地,包含 Python/Go 示例、Mermaid 状态机与大型平台十亿级对账方案。
2026-04-22 · architecture / fintech
系统拆解支付与交易场景下的实时风控引擎:三层防线、规则引擎(Drools/Aviator/CEL)、特征平台、画像、图风控、ML 打分、决策编排与 Champion-Challenger,辅以 Go 代码与分层架构 SVG。
2026-04-13 · architecture
流处理的 exactly-once 语义在工程上到底有多难?窗口计算的语义陷阱是什么?本文深入 Flink 的 checkpoint 机制、事件时间与处理时间的工程影响,对比 Kafka Streams 与 Flink 的架构差异。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。