企业级实时数据平台建设:利用存算分离 Kafka 实现低成本、高可靠入湖

作者:费红健

本文整理自 Apache 2026 技术分享《实时湖仓管道:分离式 Kafka 中的原生入湖与内嵌计算》。

存算分离 Kafka 带来的变化,不只是 Broker 变得更轻、存储可以独立扩展,以及容量与计算能够分别弹性伸缩。

图 1:Kafka 协议保持不变,Broker 计算层与远端 Segment 存储层解耦,二者可以独立扩缩容。

更重要的是,Kafka 的标准协议与实时数据面得以保留,而消息的长期持久化不再紧密绑定 Broker 本地磁盘。当数据底座完成存算解耦,开放表格式、Catalog 与托管运行时也逐渐成熟,同一份 Topic 数据便可以原生走向两条不同的价值路径:

  • 一条是 Table:把持续到达的消息沉淀为 Iceberg 开放表,让实时数据成为可以被多种引擎长期复用的资产。
  • 另一条是 SQL:让消息到达后立即参与过滤、窗口、聚合与路由,持续产生面向业务的实时结果。

但"原生"并不意味着处理过程被省略。Table 侧仍然要处理记录映射、Schema 演进、CDC、原子提交、Exactly-once 与小文件治理;SQL 侧也需要独立的运行时、资源隔离、故障恢复和任务级观测。真正发生变化的,是这些能力由谁长期承担,以及用户需要面对多大的外部责任边界。

本文以云消息队列 Kafka 版的 Topic 消息入湖与内置流计算为例,回答三个问题:

  1. 存算分离为什么会成为原生 Table 入湖与实时 SQL 计算的共同底座?

  2. 一批 Kafka 消息如何经过 Schema、CDC、原子提交与故障恢复,最终成为可信的开放表版本?

  3. Table 与 SQL 各自解决什么问题,又应该如何划分能力与运行时边界?

存算分离之后:一份数据,两条价值路径

在很多实时业务里,同一条事件会同时拥有两种价值:

  • 第一种价值发生在当下。例如,订单创建后立刻更新指标,风控事件到达后立即判断,日志进入 Kafka 后实时聚合并触发告警。它强调低延迟、持续计算和快速产出结果。
  • 第二种价值沉淀在未来。数据需要进入开放表,用于离线分析、特征工程、模型训练、历史回溯、审计与跨引擎查询。它强调开放格式、长期可读和稳定治理。

因此,平台需要提供两条彼此独立、又能共享底层数据基础的路径:

  • TABLE 路径: 把消息持续转化为开放表,形成可长期复用的数据资产;
  • SQL 路径: 让事件到达后立即参与过滤、窗口、聚合和路由,持续产生实时结果。

图 2:TABLE 产生开放资产,SQL 产生实时结果;两者共享存算分离的 Kafka 底座。

这不是要把两类工作塞进同一个运行时,而是给它们一个共同的数据起点,并分别设置清晰的责任边界。TABLE 关心的是"这张表能否长期正确";SQL 关心的是"这段计算能否持续、独立、可观测地运行"。

持续入湖平台化,需要三个前提

过去,入湖通常以一条独立数据管道存在:准备计算集群,部署 Flink 或 Spark,维护 Connector,再接入对象存储和 Catalog。这个方案灵活,但也意味着用户要同时维护消息系统、计算运行时、表格式和存储系统之间的关系。

要把持续入湖从"用户自己搭一条管道"变成"平台提供一种关系",至少需要三个前提。

图 3:存算分离、开放格式与 Serverless 化,让持续入湖具备平台化基础。

第一,Kafka 存储与计算解耦。 消息仍通过熟悉的 Kafka 协议写入和消费,但数据的持久化不再紧密依附单台 Broker 的本地磁盘。底层存储具备独立扩展能力后,同一份数据就更容易被组织为不同的数据形态。

第二,开放格式优先。 数据不能只落成一堆彼此孤立的文件。Iceberg 这样的开放表格式提供 Snapshot、Manifest、Schema、分区演进等表级语义;Catalog 则让多种计算引擎以一致的方式发现和读取这些表。

如果是第一次接触这些概念,可以先把它们理解为一条"表版本索引链":Catalog 负责发现表、管理命名空间,并保存表元数据的入口;表元数据指向当前 Snapshot,也就是某一时刻完整、可见的表版本;Snapshot 再通过 Manifest 组织该版本引用的数据文件、删除文件及其统计信息。DataFile 保存行数据,DeleteFile 保存哪些行应当失效。查询引擎沿着这条链读取的是一张有版本、有 Schema 的表,而不是自行解释对象存储中的一堆文件。

第三,运行时 Serverless 化。 用户希望表达的是"把这个 Topic 持续写成这张表",而不是"替我长期照看一套额外集群"。资源调度、失败恢复、扩缩容和版本维护应尽可能由平台吸收。

三个条件共同改变了入湖的形态:它不必总是一项外置计算任务,也可以成为 Kafka Topic 与开放表之间的一项托管配置。

原生入湖的本质:复杂度没有消失,只是责任换了位置

如果只看第一次写入,持续入湖很容易被理解成"消息转文件"。但一张长期运行的表至少要承担五类责任。

图 4:一条可用的入湖链路,需要同时处理文件、Schema、CDC、提交和恢复。

  • 小文件治理: Kafka 的数据天然以分区、批次和时间持续到达。批次太小、分区太多或提交过于频繁,都会制造大量小文件,进而放大元数据读取、查询规划、存储请求和后台合并的成本。
  • Schema 演进: 业务字段会新增,必填字段可能放宽为可选,数值精度也可能扩大。入湖链路必须判断哪些变化兼容、如何更新表结构,以及不兼容时应如何阻断和告警。
  • CDC 还原: 对数据库变更日志而言,Insert、Update、Delete 不是三种普通消息,而是在描述一张表的当前状态。入湖系统需要把事件语义转化为 DataFile 与 DeleteFile,并在读取时还原一致视图。
  • 原子提交: 文件上传成功,不等于新版本已经生效。只有当一组数据文件、删除文件和元数据作为同一个 Snapshot 原子提交后,下游才能看到一个完整的新版本。
  • 失败恢复: 任务可能在写文件之后、提交之前宕机,也可能在进度推进的边界失败。恢复机制既要允许安全重放,又要保证同一批数据不会在逻辑上重复生效。

这五件事不会因为采用原生能力而消失。变化的只是:它们从用户可见的外部任务,进入平台内部被统一承担。

1. 三种路径,三种责任划分

围绕 Kafka 入湖,常见方案大致可以分为三类。

图 5:Connector、生态计算平台和原生入湖都能完成任务,核心差异是运行时与表级责任的归属;代表产品与能力状态以发布时信息为准。

  • Connector 路径接近消息系统,部署直接,适合已有 Connect 体系、转换逻辑相对明确的团队。用户通常仍需关注 Connector 集群、任务并发、版本兼容和表提交行为。
  • 生态计算平台路径最灵活。Flink、Spark 等引擎可以承载复杂清洗、关联、状态计算和多目标写入,也拥有成熟的工程生态。相应地,用户需要运营额外运行时,并理解计算 Checkpoint、Sink 提交与表 Snapshot 之间的关系。
  • 原生入湖路径面向更聚焦的需求:当任务主要是把 Kafka 数据持续、可靠地沉淀为开放表时,由平台托管格式转换、Schema 感知、事务提交、恢复和表维护,可以显著缩小用户需要照看的系统边界。

三条路径并不存在绝对优劣。复杂关联、定制算子、多路加工仍适合专业计算平台;已经标准化的持续入湖,则更适合被收敛成产品能力。选择方案时,关键问题不是"谁的链路图更短",而是"团队希望长期拥有哪部分复杂度"。

2. 从 7 个外部节点到 3 个

在本文的示意链路中,传统外置方式包含 7 个用户可见节点:Kafka、Record Mapping、Schema、File Layout、Commit、Recovery,以及 Iceberg + Object Storage。任何一处升级、抖动或配置变化,都可能跨系统传导。

在原生模式下,对外呈现为 3 个用户可见节点:Kafka Topic、Iceberg Table 和 Object Storage。Record Mapping、Schema、File Layout、Commit 与 Recovery 仍然存在,只是被收进平台内部。

图 6:示意链路中,用户可见节点由 7 个收敛为 3 个;内部仍完整执行映射、Schema、布局、提交与恢复。

以当前产品术语来说,用户可以在原有 Topic 上启用消息入湖配置,将数据持续写入 OSS Table Bucket 中的 Iceberg 表 。它不是复制出一个新的 Kafka Topic,而是在原数据源上建立一条托管的表关系。

这种变化最重要的价值不是"少画了几个框",而是故障域变小:

  • 不需要为单一入湖目的单独维护一套外部计算集群;
  • 不需要在多个控制面之间反复同步任务状态;
  • 表提交与消费进度可以在同一托管链路内协调;
  • Schema、Compact、Snapshot 清理等能力不再由每条任务各自实现。

换句话说,原生入湖没有取消处理,而是改变了处理的所有权。

从消息到表:一个可信 Snapshot 如何诞生

把链路拉近看,一批 Kafka 消息从读取到成为开放表的一部分,通常要经过以下步骤。

图 7:消息经过映射、Schema 与 CDC 处理后形成候选文件,只有原子提交完成才成为可见 Snapshot。

首先,系统从一个或多个 Partition 读取一批确定的 offset 范围,并记录这批输入的边界。随后按照配置把消息 Key、Value、Header 或时间戳映射为表字段。

接下来 是 Schema 感知。假设业务把 amountDECIMAL(10,2) 扩大为 DECIMAL(12,2),把 country 从必填放宽为可选,又新增了可选字段 channel STRING。这些变化的共同点是:旧数据仍可以被新 Schema 合法解释,因此可以在受支持的演进规则内更新表结构。反过来,如果新类型无法兼容旧数据,系统就不应静默猜测,而应阻断提交并暴露错误。

图 8:类型提升、字段可选化和新增字段的 Schema 演进示例。

然后 ,系统根据普通追加或 CDC 语义生成候选 DataFileDeleteFile ,并构建新的 ManifestSnapshot 元数据。此时文件可能已经写入存储,但对读者仍不可见。

最后 一步才是提交:Catalog 中的 metadata location 经过条件更新,从 metadata N 切换到 metadata N+1,后者引用新的 Snapshot。更新被确认成功后,整批数据才一次性可见。若发生条件冲突,metadata location 仍指向旧版本,需要基于最新 metadata 重建提交;若提交结果未知,则必须先刷新 current metadata,确认上一次提交究竟是否成功,再决定下一步。两种情况不能混为一谈。

图 9:文件落盘不代表版本生效;Catalog 指针成功切换后,新 metadata 引用的 Snapshot 才整体可见。

这就是开放表里一个非常重要的边界:文件是物理载体,Snapshot 才是逻辑版本。

1. CDC:把事件流还原为当前视图

CDC 场景进一步说明了为什么入湖不能只做格式转换。

假设源表以主键 id 识别一行数据:

  • Insert 会新增一条记录,可写入 DataFile;
  • Delete 需要写入针对该主键的 Equality Delete;
  • Update 可以理解为"删除旧主键对应的行,再写入新版本"。

这里的 Equality Delete,可以理解为"按一个或多个等值字段匹配的逻辑删除"。在本文讨论的实现中,它不会原地修改旧 DataFile,而是把需要失效的主键值写入 DeleteFile;读取时,引擎将 DeleteFile 与 DataFile 合并,过滤匹配的旧记录。因此,一次 Update 在表里表现为"旧值失效 + 新值写入",最终读者看到的是当前视图,而不是变更事件的简单堆叠。

图 10:Insert、Delete、Update 被转化为 DataFile 与 Equality Delete,查询时合并为一致的当前视图。

读取时,计算引擎并不是简单拼接所有 DataFile,而是结合 DeleteFile 过滤已经失效的记录,得到当前 Snapshot 对应的逻辑视图。

这里有两个容易忽略的前提。第一,CDC 必须具有稳定且可识别的主键,否则系统无法准确表达"删除的是哪一行"。第二,源端事件顺序和重复投递语义必须清晰,否则同一主键的多次更新可能被错误还原。

因此,CDC 入湖的配置表面上可能只有几个选项,背后却同时连接了消息顺序、主键语义、文件组织和表版本管理。

2. Exactly-once 不等于"物理上只写一次"

在分布式系统中,失败可能发生在任何边界。一个典型场景是:文件已经写完,Snapshot 还没提交,任务突然宕机。

恢复后,如果系统无法确认旧文件是否已经生效,最安全的选择往往是重新读取并重写这一批数据。于是物理存储中可能先后出现 File-Set-A 和 File-Set-B。

图 11:offset 100--199 可能物理写入两次,但只有与进度绑定成功的 Snapshot 42 逻辑生效一次。

图中的例子从 orders-0 的 offset 100--199 开始。初始状态是 Snapshot 41,已确认进度为 99。第一次尝试写出了 File-Set-A,却在提交前失败;故障恢复后,同一批数据被重放并生成 File-Set-B。只有当 Snapshot 42 与消费进度 199 被一致地确认后,这 100 条事件才对下游可见,下一批从 offset 200 开始。

因此,Exactly-once 的准确含义是:同一批输入即使经历重试,最终也只在表的逻辑版本中生效一次。

它并不承诺底层永远只产生一份物理文件。未被任何有效 Snapshot 引用的文件可以由后台游离文件清理机制回收。

要实现这个语义,仅有 Iceberg 的原子 Snapshot 还不够,还需要把"输入进度"与"表版本生效"协调起来。当前消息入湖文档将消费进度保存在 Kafka Leader 元数据中,并由托管链路完成故障后的续传与去重;具体能力边界仍应以发布时的产品文档为准。

写入只是开始:让表长期健康且保持开放

持续写入的表即使语义完全正确,也可能随着时间变得越来越难用。

假设数据来自多个 Kafka Partition,每个 Partition 都以很短的周期提交文件。一天以后,表中可能出现大量只有几百 KB 或几 MB 的文件。查询引擎需要打开更多文件、读取更多元数据;后台也要付出更多请求和调度成本。

图 12:小批次、多分区与频繁提交会持续制造碎片,并放大元数据、规划、合并和请求成本。

因此,长期运行还需要三类维护动作:

  • Compact: 把多个小文件合并为更适合读取的大文件,并优化数据布局;
  • Snapshot 过期清理: 删除超过保留策略、不再需要的历史版本引用;
  • Orphan File 清理: 回收提交失败或重试后未被有效 Snapshot 引用的游离文件。

图 13:Partition、时间范围与文件统计逐层缩小候选文件;数字仅为查询机制示意,并非维护前后的性能实测。

表维护与查询剪枝解决的是两个相关但不同的问题:前者控制长期碎片和元数据规模,后者利用当前表的分区与统计信息,减少某一次查询真正需要扫描的文件。图中以一个独立的日志查询为例:查询 2024 年 1 月 1 日 10:00--11:00、level='ERROR'status_code >= 500 的记录。候选文件先后经过分区、Manifest 和文件级统计过滤,从 2380 个缩小到 940、420,最终只剩 189 个。这组数字不是 Compact 前后的对比。

这些数字用于解释机制,并不代表某个真实业务的固定性能提升。真正的收益会受到数据分布、文件大小、分区策略、统计信息质量和查询条件影响。重要的是,开放表并非"把所有文件列出来再全量扫描",而是通过多层元数据尽可能让引擎少读文件、少做 I/O。

开放表的价值,在于不绑定单一引擎

数据进入湖仓后,如果只能由写入它的系统读取,就还称不上开放资产。

完整的开放性至少包括三层:

  • 格式开放: 数据文件与表元数据遵循 Iceberg 等开放规范;
  • Catalog 开放: 引擎可以通过标准化入口发现 Namespace、表和 Snapshot;
  • 消费开放: Spark、Flink、Trino、PyIceberg 以及云上分析引擎可以按各自场景复用同一份表数据。

图 14:Catalog 负责发现表和版本,Iceberg 元数据组织文件,多种引擎读取同一份当前表状态。

OSS Tables 提供一个兼容 Apache Iceberg REST Catalog 的 API 端点,该兼容层优先保持与 AWS S3 Tables 的行为一致。对上层引擎而言,Catalog 先返回表的元数据位置,再由 Snapshot、Manifest List、Manifest 逐级定位 DataFile 和 DeleteFile。

这种分层设计带来一个长期收益:写入链路不需要预先决定未来所有计算方式。 今天可以用 Trino 做交互式查询,明天用 Spark 做批处理,后天再把表用于特征工程。计算引擎可以变化,数据资产不必随之搬迁。

当然,"兼容接口"不等于所有扩展能力都完全一致。不同引擎版本、Catalog 接口和 Iceberg 特性的支持矩阵,仍需以当前官方兼容性文档为准。

SQL 补全另一半:让事件在到达时产生结果

TABLE 路径解决了长期沉淀问题,但很多业务不愿等数据先变成表再计算。

例如,对支付成功订单按用户做一分钟窗口聚合,把结果持续写回一个结果 Topic;或者实时过滤异常日志、提取字段、按条件路由到不同下游。这些需求关注的是事件到达后的即时处理,更适合交给 SQL 路径。

图 15:Kafka Topic 映射成流式表,经 SQL 持续处理后写入结果 Topic。

一个概念化的逻辑可以写成:

复制代码
SELECT
  user_id,
  TUMBLE_START(event_time, INTERVAL '1' MINUTE) AS window_start,
  SUM(amount) AS paid_amount
FROM orders
WHERE status = 'PAID'
GROUP BY
  user_id,

这段 SQL 的重点不是具体语法,而是责任边界 :Kafka 提供持续输入和输出,SQL 运行时负责窗口状态、计算资源、失败恢复与观测。各任务独立部署,避免一个任务的资源波动直接影响其他任务。

图 16:产品入口保持统一,每个 SQL 任务使用独立运行时、资源视图和故障域。

TABLE 与 SQL 因而不是替代关系:

  • 只需要把原始消息可靠沉淀为开放表,优先考虑消息入湖;
  • 需要到达即算的过滤、窗口、聚合和路由,使用流计算;
  • 需要复杂关联、自定义算子、跨系统编排或成熟作业治理,仍可选择外部 Flink 等生态计算平台;
  • 同一份数据既要实时结果又要长期资产,两条路径可以并行存在。

这也能避免一个常见误区:为了让架构看起来"统一",强行让一种运行时承担所有任务。真正合理的统一,应发生在数据与产品入口,而不是牺牲不同负载应有的隔离。

选择方案之前:先问清四个边界

面对一条新的 Kafka 入湖需求,可以先用四个问题划定边界。

第一,数据只是持续落表,还是还要做复杂计算? 如果只有字段映射、Schema 演进和 CDC 还原,原生能力能减少外部运行时;如果包含复杂 Join、定制 UDF 或多流状态,专业计算引擎更合适。

第二,谁负责长期表健康? 不能只确认"第一批文件是否写成功",还要明确小文件合并、Snapshot 过期和游离文件清理由谁执行、如何观测。

第三,故障后的正确性边界是什么? 需要明确输入进度、文件写入和 Snapshot 提交如何关联;如果下游还有二次写出,端到端 Exactly-once 还依赖目标系统的事务或幂等能力。

第四,未来由哪些引擎消费? Catalog 接口、Iceberg 版本和具体特性需要与 Spark、Flink、Trino 或其他引擎的支持矩阵逐项对齐。

这四个问题能把一次"产品选型",转化为一次可验证的责任划分。

写在最后:让数据同时服务当下与未来

回到本文的主线:存算分离 Kafka 为 Table 与 SQL 提供了共同的数据底座,而这篇文章重点回答的是,如何让 Kafka 消息持续成为一张可信、开放、健康的表。

原生入湖的价值,不是把必要步骤从架构中删除,而是把 Schema、CDC、原子提交、失败恢复和后台维护收进托管边界; 把用户需要长期照看的外部节点,从一条复杂管道收敛为更稳定的 Topic---Table 关系。

与此同时,实时 SQL 为同一份数据提供另一条价值路径:事件到达后立即参与计算,持续产生面向业务的实时结果。

本文对实时 SQL 只做整体定位与边界说明。关于它的运行机制、时间语义、状态管理和一致性实践,我们将在后续文章中继续展开。

最后可以把整套架构浓缩成两句话:TABLE 让消息成为开放资产,SQL 让事件产生实时结果。

两者共享同一个 Kafka 数据起点,各自保持清晰的运行时和责任边界。数据既能在当下创造价值,也能在未来被不同引擎反复使用。

需要说明的是,截至本文整理时(2026 年 8 月),Topic 消息入湖与流计算的开放区域、实例版本、支持语法和公测状态仍在持续演进。消息入湖当前文档标注为公测能力,并对 Serverless 实例版本和地域有要求;流计算的地域、SQL 能力和端到端一致性也存在明确限制。正式开通或发布前,请以控制台与最新官方文档为准。

相关链接:

1AI 时代,实时入湖正在告别 ETL:从 Kafka 到 Iceberg 的架构减法

2 消息入湖:将 Kafka Topic 数据持续写入 OSS Table Bucket

https://help.aliyun.com/zh/oss/user-guide/data-ingestion-into-the-data-lake

3 OSS Tables 快速入门

https://help.aliyun.com/zh/oss/user-guide/quick-start

4 Iceberg REST API 兼容性说明

https://help.aliyun.com/zh/oss/user-guide/iceberg-rest-api-compatibility

5 云消息队列 Kafka 版流计算能力说明

https://help.aliyun.com/zh/apsaramq-for-kafka/cloud-message-queue-for-kafka/user-guide/flow-computing-capability-function-description

6 流计算架构与高可用

https://help.aliyun.com/zh/apsaramq-for-kafka/cloud-message-queue-for-kafka/user-guide/stream-computing-architecture-and-high-availability

7 流计算快速入门与使用限制

https://help.aliyun.com/zh/apsaramq-for-kafka/cloud-message-queue-for-kafka/user-guide/stream-computing-quick-start

线下沙龙:

这条实时链路的下一步,往往是被 AI Agent 消费。Agent 能不能在生产环境里跑得下去,很大程度上取决于上游数据能不能实时可信------上下文靠 T+1 拼出来,时序敏感任务就会频繁失准。

8 月 28 日下午,上海徐汇滨江有一场线下沙龙,就聊一件事:怎么让实时数据以低延迟、高可靠、可弹性的方式,持续供给模型与 Agent。

三位一线工程师沿数据链路依次展开:实时数据流怎么加工成模型可消费的上下文、数据管道要补齐哪些能力才算 AI-Ready、流接入/流计算/入湖能不能收敛进同一个平台。

如果你正在把 AI 应用、Agent 或 RAG 推向生产环境,欢迎来现场。

点击链接,立即报名:https://survey.aliyun.com/apps/zhiliao/D46NlVre1

相关推荐
探索云原生4 小时前
KubeClipper 1.7.0 发布:Operation 优化与 Kubernetes 1.37 支持
linux·docker·云原生·kubernetes·go
程序员天天困5 小时前
Kafka 接入 AI 的三条路线:MCP 提案、会话记忆与实时上下文
大数据·后端·kafka
MrSYJ8 小时前
Veth pair 细讲
docker·云原生·容器
Elastic 中国社区官方博客8 小时前
将 Vercel 数据导入 Elastic:无需安装任何东西的无服务器可观测性
大数据·运维·elasticsearch·搜索引擎·云原生·serverless·全文检索
聚搜云——JuSouClouD8 小时前
在阿里云代理商渠道买轻量服务器,带宽套餐支持自选吗?
服务器·阿里云·云计算
聚搜云——JuSouClouD9 小时前
2026找阿里云代理商采购GPU服务器,有没有额外折扣?
服务器·阿里云·云计算
运维栈记9 小时前
使用 MinIO Client (mc) 将自建 MinIO 数据备份至阿里云 OSS
运维·阿里云
懂软件的胡子个哥10 小时前
微信工单系统如何基于 WechatApi 做消息分流和状态流转
运维·分布式·微信·架构·企业微信
阿里云云原生1 天前
云栖剧透丨四场论坛,看清智能体走进生产的关键路径
云原生