暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

实时打通 Postgres→Iceberg:Debezium、Kafka Connect 的局限何在?

吴英骏
来源|RisingWave 官网
过去一年,数据基础设施的目光几乎都集中在 Postgres 和 Apache Iceberg 上。Databricks 收购 Neon、Snowflake 收购 CrunchyData,更加坚定了业界对这两大方向的认可。Postgres 已经稳固成为 OLTP 领域的事实标准,而 Iceberg 则凭借开放的表格式和广泛的生态支持,逐渐取代部分专有云数据仓库,成为现代数据湖的核心选择
但把这两者实时打通,仍然是一个工程难题。要想让 Iceberg 表持续同步 Postgres 的实时变更数据,必须依赖 CDC(Change Data Capture)管道。业界常用的工具如 Debezium 和 Kafka Connect 已存在多年,看起来似乎已经给出了答案。我也曾这样认为。
然而,在深入分析生产环境的真实案例,与多家工程团队深入讨论后,我发现:从 Postgres CDC 到 Iceberg 的实时数据摄取远未成为“已解决的问题”。无论是上游的数据捕获,还是下游的数据写入,都存在着不容忽视的细节问题。这些问题集中在以下几个方面:端到端 Exactly Once 语义保障、故障恢复机制、快照与回填性能、Schema 演进、Iceberg 写入一致性,以及复杂的多组件运维架构
接下来,我会逐一拆解这些挑战,并分享一些真实场景中的经验教训。

Exactly Once 保障与故障处理

构建一个可靠的 CDC 管道,首先面临的最大挑战就是实现端到端的 Exactly Once 语义。多数工具只能做到 At Least Once,这在概念上看似可接受,但一旦遇到真实生产故障,重复数据、数据丢失和人工重放的问题就会暴露无遗。

上游故障恢复
Postgres 的 replication slot 虽然设计得相当稳健,但在生产环境中依旧会遇到极端情况。如果 Postgres 崩溃、网络中断,或 replication slot 因 WAL 保留策略被意外清理,大多数 CDC 工具都无法平滑恢复。一个常见的问题是 CDC 读取器(如 Debezium)和下游系统之间的 LSN 偏移错位。如果恢复点不准确,要么会漏掉事件,要么会重复消费并下发给下游。
在实践中,我见过不少团队在 replication slot 丢失后,被迫重新全量快照数据库。这可不是小事——当数据量达到数百 GB 或者 TB 级别时,全量快照既慢又昂贵,如果还涉及锁表操作,更会对在线业务造成直接影响。
我记得一家电商平台的团队,他们运行 Debezium 连接 Postgres。一次短暂的数据库宕机导致 replication slot 丢失。最后他们只能重跑所有表的快照,花了近 10 小时才完成恢复,期间消耗了大量 I/O,而数据分析团队则被迫等待,业务几乎陷入停滞。
下游故障隔离
下游的 Iceberg 或 Snowflake 同样可能发生写入失败或短时不可用。如果没有内置的缓冲或反压机制,很多 CDC 管道会被迫阻塞。一旦 Kafka Topic 堆积过多且超过保留期,就会面临数据丢失或重放的两难选择,最终又回到手动补数据或重新同步的老路。
有一次,我们遇到过一个客户,他们的管道因为 AWS S3 的短时异常导致 Iceberg Sink 持续失败,结果 Debezium 和 Kafka 的消息不断积压,反压直接传递到上游的 Postgres。由于 Debezium 在这种情况下无法及时提升 low LSN,Postgres 的 WAL 日志不断堆积,最终形成了巨大的 replication lag。等他们发现问题时,WAL 几乎占满磁盘空间,差点拖垮主库。这种“连锁反应”是典型的 CDC 管道噩梦,也是许多团队在使用 Debezium 时忽略的隐藏风险。
端到端 Exactly Once 的难题
即便 Debezium、Kafka、Flink 等组件各自实现了 checkpoint 和重试机制,要想把它们拼接起来,真正实现端到端的 Exactly Once 依然困难重重。组件之间的交接点往往会留下重复或遗漏数据的风险,尤其是在 backfill 阶段。
一个特别值得提及的问题是快照(snapshot)阶段与 WAL 增量日志的对齐
最简单的做法是,在读取快照时锁住上游表,阻止新的写入,等快照完成后再开始消费 WAL 并释放锁。这种方式虽然保证了数据一致性,但会直接阻塞上游写入,显然不适用于大多数线上业务。
如果不锁表,就必须解决一个棘手问题:在快照阶段上游新增的数据,既不能漏读,也不能被重复消费。
像 RisingWave 和 Flink CDC 这样的系统,会在消费快照的同时持续读取 WAL,并通过下游的状态表对齐 snapshot 和 WAL 的数据,从而保证数据不丢失且不阻塞上游写入。
此外,在恢复和重启场景下,如果没有一个强一致的 checkpoint 机制,或者 checkpoint 与 Kafka offset 对齐不够严谨,就可能导致数据多读或少读。对 WAL offset 的精确管理是整个链路能否保证 exactly once 的关键,而这往往需要上层 CDC 引擎自己来承担。
Iceberg 也带来独特挑战。它并不天然支持主键级别的幂等更新,如果只是单纯地进行 append 或批量写入,而没有通过 equality delete 或 merge-on-read 模式,很容易出现重复记录。这些重复一旦落盘,后续清理代价很高。
对于金融或合规类业务,这种问题是无法容忍的。我曾帮助过一家交易公司调试他们的 CDC 管道,结果因为 snapshot 与增量数据在恢复时出现对齐问题,加上 Iceberg 端没有正确处理幂等更新,导致下游的资金头寸计算出错。最后,他们不得不在 Iceberg 表上额外构建复杂的去重逻辑,这无形中增加了管道的维护难度和延迟。

性能与资源消耗

CDC 管道的性能问题往往在从 PoC 进入生产阶段时才会真正显现出来。CDC 工具既要处理首次快照,又要应对持续的增量变更,这两部分的挑战完全不同。

Replication Slot 资源压力
Postgres 的 replication slot 是有限资源。在实际生产环境中,通常是一个数据库对应一个 replication slot,而不是每张表各自创建一个。比如在 RisingWave 的实现中,一个 shared source 对应一个上游 Postgres 实例,并共享同一个 replication slot。Postgres 启动时可以创建多个 replication slot,这些 slot 可能同时在运行,也可能空闲,但真正活跃的 slot 通常与订阅者一一对应。
然而,当 Debezium 等工具被部署在多租户或多实例环境中时,如果配置不当,可能会为每个 connector 或每个订阅场景单独创建 slot,导致 slot 过多,进而拖慢 WAL 日志的清理和 Vacuum 操作。长期积压的 WAL 不仅占用大量磁盘,还会增加数据库的 I/O 压力。
我曾经接触过一个客户,他们的数据库虽然只建了 2 个 replication slot,但由于 Debezium 的消费速度跟不上 WAL 的生成速度,WAL 堆积了数百 GB,导致归档进程跟不上。最后只能临时提高 Debezium 的消费速率,并手动清理 WAL 才稳定下来。
快照与回填的性能瓶颈
首次快照往往是所有团队遇到的最大难题。传统 CDC 工具在做快照时,通常会采用单线程的顺序扫描,这种方式在大表(上亿行)上会非常缓慢,常常需要几个小时甚至几天才能完成。如果中途出错,你几乎只能从头再跑一遍,既浪费时间又占用资源。
更棘手的问题是快照与 WAL 增量数据的对齐。一些实现为了保证一致性,会在快照阶段锁住上游表,防止新写入,然后在快照完成后再开始消费 WAL。这种方式虽然简单,但代价是直接阻塞线上写入,不适用于大多数生产环境。
RisingWave(以及 Flink CDC)的做法是在快照的同时同步消费 WAL,并在下游通过状态表将 snapshot 和 WAL 进行精确对齐,确保既不丢数据,也不会阻塞上游写入。
我曾经见过一家 SaaS 公司尝试用 Debezium 进行迁移,他们的大表快照直接拖慢了线上 OLTP 性能,不得不每天晚上暂停业务来跑快照,白天则停掉 CDC。原本两天能完成的任务,最终硬生生跑了一周才搞定。
大字段内存问题
Postgres 的 TOAST 字段(如 JSON 大对象)也是个难点。Debezium 在读取时常会把这些大字段一次性加载到内存里,如果同时有多个大事务,内存直接溢出。这种 OOM 问题在生产上并不少见,很多团队只能通过拆字段、压缩数据等方法临时缓解。

数据类型与 Schema 演进

Schema 变更是 CDC 管道中最容易被低估的挑战。在现代 Postgres 中,表结构的变化是家常便饭:增加字段、修改类型、重建索引等等。这些变化沿着 CDC 链路传播时,很容易造成下游数据不一致或管道崩溃。

分区表与 TOAST 的支持
Debezium 对分区表和 TOAST 的支持都不够好。对于 TOAST 字段,它需要开启 full replica identity 模式,这会显著增加 WAL 的大小;而分区表的新增分区无法自动发现,往往需要重启 Connector,风险不小。
多下游环境的 Schema 演进
多下游同步场景更是难上加难(例如同时写 Iceberg、Snowflake、Redshift)。Postgres 增加一列字段,可能就要:
  • 修改 Debezium 配置;
  • 更新 Kafka Schema Registry;
  • 调整 Flink 作业;
  • 变更 Iceberg 表结构。
很多团队花了大量时间写自动化工具来同步 Schema,但稍有不慎就会出问题,比如类型不兼容、默认值缺失等。


Iceberg 写入与一致性

Iceberg 更偏向批处理,而 CDC 流是行级的持续变更。如何让二者平衡,是另一个不容忽视的问题。

批量提交与事务边界
为了保持一致性,CDC 事件必须先聚合成批次再写入 Iceberg。如果批次在提交过程中失败,Iceberg 没有自动回滚的机制,容易造成部分提交。你需要额外的机制来检测并重放失败批次,否则就可能发生数据缺失或重复。
小文件问题与 Compaction
另一个经典问题是 小文件过多。如果提交过于频繁,就会产生大量小 Parquet 文件,严重拖慢 Iceberg 查询,因为元数据层需要维护成千上万个文件。团队往往要额外跑 Compaction 任务,而这会增加延迟和维护开销。


运维复杂度

最后,Postgres 到 Iceberg 的 CDC 管道在运维上也极其复杂。典型架构是:Debezium 抓取 CDC → Kafka 缓冲 → Flink 转换 → 自定义 Iceberg Sink。每个环节都要单独监控、调优和恢复。

我遇到过一些团队,几乎需要单独的 SRE 团队来“养”这套 CDC 系统。排查故障时要翻好几套日志,从 Debezium 到 Kafka 再到 Flink,每个地方都有自己的 offset 和 checkpoint。哪怕只是重启一个 Connector,都可能带来数据重放或丢失的问题。


RisingWave 的方案

RisingWave 之所以出现,就是为了针对这些痛点提供一个统一的解决方案。我们希望用一个集成的流式数据库,来直接从 Postgres 抓取 CDC 数据,并以 端到端 Exactly Once 语义 安全写入 Iceberg。

在 CDC 抓取层面,RisingWave 采用了 Debezium Embedded Engine 作为底层 WAL 解析引擎,但我们在实践中对其做了大量深度优化。Debezium 本身并非为高吞吐、低延迟的实时管道而生,在大事务、复杂 schema 演进和 offset 管理上都有不少坑点。RisingWave 的改进包括:

  • 针对大事务和高并发场景改进了 WAL 解析和内存管理机制,显著降低了内存占用。

  • 优化了 offset 管理和 LSN 持久化逻辑,确保故障恢复时能从正确位置继续消费,而不需要全量重跑。

  • 提升了 schema 解析效率,解决了 Debezium 在复杂 schema 更新时的延迟问题。

  • 将 Debezium 与 RisingWave 内部的 log store 和 state table 紧密集成,实现 snapshot 与 WAL 的精准对齐。

在整体设计理念上,RisingWave的关键特性包括:
  • 强大的故障恢复能力:内部 LSN 管理保证即便出现故障,也能无缝恢复,无需重新快照。
  • 下游隔离:通过 持久化 log store 实现 sink decouple,当下游 Iceberg 出现故障时,上游 CDC 采集不会受阻,恢复后可按顺序补齐。
  • 高效快照:支持 无锁并行快照,在不影响 OLTP 业务的前提下大幅缩短全量加载时间。
  • 原生 Iceberg 支持:提供批量写入、Equality Delete、事务提交和自动 Compaction。
  • Schema 自动演进:能够自动检测并同步上游的 schema 变化,减少人工维护成本。
  • 易用性与可观测性:一个系统即可完成 CDC 采集、流式转换和 Iceberg 写入,省去 Debezium-Kafka-Flink 那种复杂架构。


总结

乍看之下,从 Postgres CDC 到 Iceberg 似乎是一个已经被解决的问题,但实际情况却并非如此。上游复制的复杂性、快照和回填的性能瓶颈、Schema 演进带来的不一致、Iceberg 写入的事务保障,以及多组件带来的运维负担,使这个问题仍然充满挑战。

RisingWave 的目标是彻底简化这一切。

通过在一个系统中同时处理 CDC 抓取、流式转换和 Iceberg 写入,RisingWave 不仅实现了高可靠性、低延迟和端到端的 Exactly Once 语义,还提供了 端到端的自动 Schema 变更能力。无论上游 Postgres 表结构如何演进,RisingWave 都能自动检测并传播这些变化到下游 Iceberg,避免手动修改 Debezium 配置、Kafka Schema Registry 或下游表结构所带来的繁琐工作。

一个典型案例是西门子(Siemens)

在引入 RisingWave 之前,西门子团队使用 SQL Server CDC,整个链路是 SQLServer → Debezium → Kafka → RisingWave。这条管道不仅需要维护多组 Debezium 配置参数,还要管理 Kafka 及其 offset,整体架构复杂且易出错。

在购买 RisingWave 商业版本后,他们将 CDC 管道简化为 RisingWave 直接对接上游 SQL Server,完全无需配置复杂的 Debezium 参数,也无需显式管理 Kafka 链路。对用户而言,Debezium 和 Kafka 的存在感完全消失了,RisingWave 成为一个对 CDC 数据“开箱即用”的黑盒,大幅降低了维护成本和出错风险。


近期活动

关于 RisingWave 

RisingWave 是一款基于 Apache 2.0 协议开源的分布式流数据库,致力于为用户提供极致简单、高效的流数据处理与管理能力。RisingWave 采用存算分离架构,实现了高效的复杂查询、瞬时动态扩缩容以及快速故障恢复,并助力用户极大地简化流计算架构,轻松搭建稳定且高效的流计算应用。
RisingWave 始终聆听来自社区的声音,并积极回应用户的反馈。目前,RisingWave 已汇聚了 150+ 名开源贡献者和 3000+ 名社区成员。全球范围内,已有上百个 RisingWave 集群在生产环境中部署。

技术内幕

如何上手 RisingWave 👉 新手入门教程

RisingWave 中文用户文档上线,阅读更高效!

深入探索 RisingWave 中的高可用性与容错机制

深入理解 RisingWave 流处理引擎(三):触发机制

深入理解 RisingWave 流处理引擎(二):计算模型

深入理解 RisingWave 流处理引擎(一):总览

用户案例
视源股份(CVTE)IT 流计算应用历程
尘锋 SCRM 如何使用 RisingWave 实时打宽
RisingWave 在超百亿管理规模对冲基金公司中的应用
金融科技公司 Kaito 使用 RisingWave 实现实时智能化
龙腾出行如何通过 RisingWave 实现实时数据分析

RisingWave 助力乾象投资打造实时监控平台



👇 点击阅读原文立即体验 RisingWave!

文章转载自RisingWave中文开源社区,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论