跳转到主要内容
  • Debezium Server 与 Databricks Zerobus Ingest 相结合,通过基于推送的架构将 CDC 事件直接流式传输到 Unity Catalog 的 Delta 表中。
  • 封锁入站连接的封闭私有网络现在可以安全地向外复制数据,无需中间 Kafka 消息代理或基于拉取的连接器。
  • 组织可以将原始数据库变更向外推送到湖仓,从而大幅简化构建供下游分析使用的当前状态表所需的基础设施。

运营数据库中的数据驱动着业务决策,而其中大量分析都在湖仓中进行。当数据库位于私有企业网络、客户控制的环境或受限子网中,且其网络策略阻止来自外部服务的入站连接时,将数据迁移到湖仓就变得十分困难。

许多团队需要将 PostgreSQL 的变更引入 Databricks,但拥有该数据库的团队也希望掌控捕获过程。该团队运行读取预写日志的进程,并决定哪些连接可以离开其网络。另一方面,变更会落入受治理的 Delta 表,管道和分析师可以在此基础上进行构建。

Debezium 是一种常见的开源工具,团队可以完全自主部署它,从数据库中提取变更数据捕获流。它位于数据库旁边,读取其预写日志并将事件向外推送。 Zerobus Ingest 是目标端,一个将记录直接写入 Unity Catalog Delta 表的推送接口。开源的 Debezium Server Zerobus sink 将两者连接起来,无需在捕获端和湖仓之间使用传统的 Kafka 集群。

NVIDIA 和 Databricks 的工程师合作构建了这一 sink,并将其贡献给开源 Debezium 项目。Databricks 构建了带类型的 Zerobus Ingest sink。随后,NVIDIA 贡献了 envelope 模式,该模式会落地完整的 Debezium 变更事件,以及围绕它的投递保障措施,例如幂等键和在源偏移量推进前进行持久化确认。 Zerobus Ingest sink 已在 Debezium Server 3.7 版本中发布.

本文介绍了 Debezium 和 Zerobus 各自的作用、NVIDIA 贡献给该 sink 的原始变更 envelope,以及落地的事件如何成为当前状态表或历史表。如需动手实践的分步指南,包括从本地 PostgreSQL 表到当前状态表的实时运行演示,请参阅 Databricks 社区上的配套操作指南博客. 

挑战

将运营数据库变更可靠地复制到湖仓中,必须同时解决几个问题:

  • 可靠地捕获插入、更新和删除。 一行数据被创建、修改并随后删除时,必须为每个事件生成忠实的流。这必须包括删除操作,而基于查询的“复制表”方法通常会遗漏删除。
  • 保留排序所需的证据。 重建当前状态的下游逻辑必须按源顺序应用变更,才能正确复制源表。
  • 避免使源数据库过载。 按计划轮询数据库(SELECT ... WHERE updated_at > ?) 会增加查询负载,且扩展性差。
  • 适用于私有/客户控制的网络。 当数据库位于封闭边界之后时,我们知道连接这些系统并摄取数据可能具有挑战性。
  • 避免仅仅为了传输而搭建 Kafka。 Kafka 是一个强大的事件总线,但仅仅为了将 CDC 事件从数据库移动到湖仓而运营一个集群,对于本来不需要它的团队来说是巨大的开销。
  • 落地数据,使其易于处理。 变更流必须以湖仓能够处理和查询的形式到达,而不是落入需要额外导出步骤的孤岛。

鉴于这些要求,我们需要从数据从源到 sink 流动的架构开始。

整体目标架构

在本文中,我们将探讨传统的消息总线架构与使用 Zerobus Ingest 的架构之间的对比。

使用消息总线的架构:
Architecture with a message bus: source operated capture

在许多企业环境中, 出站 连接从边界内部获得许可,远比 入站 访问容易得多。当你的团队想要运行变更流提取代理的部署时,本地推送模型可以让数据向外流向目标端。在传统设置中,这个目标端会是 Kafka 之类的消息总线。运行 Kafka 需要资源来进行容量规划,以预测处理峰值负载所需的 broker 数量以进行物理扩展,并估算消费者跟上生产速率所需的分区数量以进行逻辑扩展。这需要一个在 Kafka 部署和管理方面有经验的专职团队。

一旦数据落入 Kafka,你就有了下一个要完成的任务,即将这些事件复制到湖仓。这可以通过部署 Spark、Kafka Connector 或其他工具的摄取作业来实现。结果是形成了从 Debezium 到湖仓的两跳架构。

使用 Zerobus Ingest 的架构:
Architecture with Zerobus Ingest: Source operated capture

当你唯一的目标端是湖仓时,Zerobus 允许你绕过消息总线等中间跳。这既简化了端到端架构,也消除了为数据传输而部署和管理 Kafka 基础设施的需要。当使用 Zerobus 作为 Debezium 的 sink 时,它无需调优即可在高峰时段继续工作。

什么是 Debezium?

Debezium 是一个开源的、基于日志的变更数据捕获平台。它不轮询表,而是读取数据库的事务日志,例如 PostgreSQL 的预写日志(WAL)、MySQL 的 binlog 和 MongoDB 的变更流。然后它将每个变更作为结构化事件发出。该项目始于 2015 年,如今支持广泛的连接器生态系统(PostgreSQL、MySQL、SQL Server、Oracle、MongoDB 等)。

每个变更事件都携带一致的 envelope:

  • before — 变更前的行状态(插入时为 null)
  • after — 变更后的行状态(删除时为 null)\
  • op — 操作类型: c (创建/插入)、 u (更新)、 d (删除)、 r (读取/快照)
  • source —— 元数据:数据库、schema、表、WAL 日志序列号(LSN)、事务 ID、快照标志
  • ts_ms —— 事件时间戳

Debezium 通过日志尾随而非轮询来以低延迟捕获变更,因此对主数据库施加的负载极小,并能保持提交顺序。

独立部署(Debezium Server)与 Kafka Connect 部署

Debezium 有两种运行模式。一种运行在 Kafka Connect 上,另一种是“独立服务器”,可以部署在普通计算资源上。

 

Kafka Connect 上的 Debezium

Debezium Server(独立部署)

运行时

Kafka Connect 集群内的插件

独立的 Quarkus 应用

原生目标端

Apache Kafka(再下沉到其他系统)

通过 sink 适配器直接写入非 Kafka 目标端。(例如 Zerobus Ingest)

适用场景

Kafka 是你的规范事件总线;你需要 Connect 的分布式 worker、SMT、schema registry

你不运行 Kafka,或者你想将 CDC 直接推送到专用目标端

Debezium Server, 即独立运行时,充当源端代理,尾随事务日志并将变更事件直接发送到 Databricks 的 Zerobus Ingest,无需 Kafka 集群作为传输层。

解决方案:Debezium + Zerobus Ingest

因此我们已确定 Debezium 作为日志尾随器。现在我们需要将事件送入 Databricks。

Zerobus Ingest 是一项无服务器、基于推送的摄取服务,可将数据直接写入由 Unity Catalog 治理的 Delta 表,无需运行消息代理。生产者连接到 Zerobus 端点并流式传输记录,这些记录会落入开放格式的 Delta 表。它专为处理高吞吐量、高并发工作负载而构建。通过跳过消息代理这一步骤,我们能够简化架构,并免去为将数据移动到湖仓而扩展和运行摄取管道所需的维护工作。

与 Debezium 结合使用时,你的 CDC 管道大致如下:

  • Debezium 观察数据库日志并将每个变更转换为 CDC 事件。
  • Zerobus Ingest 将这些事件直接传输到 Databricks 并写入 Delta 表——无需 Kafka 集群作为中间传输层。
  • Databricks 在 Delta 表中接收变更流,并可将其处理为下游的精选表。

Zerobus Ingest 是仅追加的。变更事件落地后,下一步是通过执行 merge 来构建 Type-1 维度表,以获取每个给定主键组合的最新版本。

NVIDIA 的贡献:envelope 模式

Debezium 中的 Zerobus sink 提供两种表契约。 Typed 模式(默认)将每个变更事件映射到具有源自身列的表。 Envelope 模式(由 NVIDIA 贡献)将完整的 Debezium 变更事件落入固定的九列表:

  1. target_table
  2. destination
  3. partition
  4. operation
  5. idempotency_key
  6. key
  7. value
  8. source_position
  9. headers

记录可以编码为 JSON(存储在 VARIANT 列中)或 Protobuf。

Envelope 模式保留了下游处理所需的证据。source_position 携带源分区和偏移量,包括 PostgreSQL LSN。 idempotency_key 是每个事件的 SHA-256 标识,由其 destination、partition、key、operation 和 source position 派生而来,因此重新投递的事件会获得相同的 key。该 key 用于标识事件;它本身不对事件排序,也不会对表去重。 

Durability gates source acknowledgment
持久化门控源端确认:sink 为每张表发送每个连续记录组,等待 Zerobus 确认其持久化,然后才允许 Debezium 推进其偏移量。

如果后续组失败,先前已持久化的组可能会被再次投递,因此投递语义为至少一次,重复项在下游通过 idempotency_key处理。Envelope 模式还按 destination 和 operation 进行过滤,并在摄取前拒绝超大记录,因此其偏移量永远不会被提交。

Databricks 中的数据建模

一旦 CDC 事件落入 Delta,常见的 medallion 风格流程会将原始变更流转化为分析师和应用可用的内容:

  • Bronze: 按接收原样保存的原始变更事件。使用 envelope 模式时,即每个事件一行,携带其 operation、before/after 行镜像、source position(LSN)和 idempotency_key.
  • Silver: 解析后的变更记录,按 idempotency_key 去重并按 source position 排序。源数据的可用表示形式,通过解释插入/更新/删除来重建当前状态。
  • Gold: 运营数据与业务数据结合进行转换以用于报告,例如财务、绩效指标等。

有两种塑造变更流的方式值得简要提及:

  • Type-1(当前状态): 折叠变更日志,使每个 key 反映其最新值——源表的当前状态副本。
  • Type-2(历史): 保留每个版本随时间的变化,以便你可以查询数据在任意时间点的样子。

Databricks 社区上的 配套操作指南博客 使用本地 PostgreSQL 表端到端地演示了这一过程。它配置 Debezium Server 与 Zerobus sink,检查 envelope 表中的插入、更新和删除,然后使用 AUTO CDC 构建 Type-1(当前状态)表,按 source LSN 对变更进行排序。

结论

选择正确的 CDC 架构最终取决于你组织的网络约束、运维偏好和现有基础设施。 

需求 / 特性

Debezium + Zerobus(本地推送)

DIY(Debezium + Kafka + Spark)

摄取方向

基于推送(源端代理向外推送)

基于推送(源端代理向外推送到 Kafka)

网络要求

仅需要源网络具有出站访问权限

需要到 Kafka 集群 / broker 的出站访问权限

私有 / 客户网络

非常适合锁定或私有网络

适合私有网络,但需要管理 Kafka 连接

Kafka 基础设施

不需要(通过 Zerobus 直接流式传输)

需要(Kafka 集群充当中间缓冲区)

连接器管理

需要在本地运行 Debezium Server

运维开销高(需管理 Kafka、Connect 和 Spark 摄取作业)

生态系统兼容性

充分利用完整的 Debezium 连接器生态系统;envelope 模式将原始变更事件写入 AUTO CDC 的 silver 和 gold 表

充分利用完整的 Debezium 和 Kafka Connect 生态系统,并通过自定义 Spark 流式处理写入 Delta(Bronze)和 AUTO CDC 作业

通过将 Debezium Server 与 Zerobus Ingest 相结合,你可以部署一种本地推送架构,将变更直接流式传输到 Delta 表,无需 Kafka 作为中间消息传输,也不依赖云对象存储中的暂存区,从而简化端到端摄取路径。

这样,PostgreSQL 捕获工作仍由拥有该数据库的团队控制,而数据则写入 Unity Catalog。 

快速开始

要自行构建此管道,请遵循 Databricks 社区上的分步指南。该指南将 PostgreSQL 变更通过 Debezium Server 和 Zerobus Ingest 写入 Unity Catalog 表,然后使用 AUTO CDC 构建当前状态表。有关 Zerobus Ingest 的设置及其其他摄取接口,请参阅 Zerobus Ingest 文档.

常见问题

什么是 Debezium Zerobus Ingest sink?

它是 Debezium Server(独立的 Debezium 运行时)中的一个 sink,可将变更事件直接发送到 Zerobus Ingest。Zerobus Ingest 将其写入由 Unity Catalog 治理的 Delta 表,因此捕获与湖仓之间无需 Kafka 集群。NVIDIA 与 Databricks 合作完成了这项开源贡献。

什么是 envelope 模式?

Envelope 模式将每个完整的 Debezium 变更事件写入固定的九列表,而不是将其映射到源自身的列上。该模式由 NVIDIA 贡献给该 sink。它保留操作、键、值、源位置以及用于下游处理的幂等键。默认使用 typed 模式。

该 sink 是否对每个变更恰好投递一次?

不是,投递语义为至少一次。如果后续一组记录失败,先前已持久化的一组记录可能会被再次投递。每个事件都携带 idempotency_key,因此你可以在下游据此去重。

如何将变更流转换为当前状态表?

使用 AUTO CDC 构建 Type-1 表,保留每个键的最新版本。按源 LSN 对变更排序,使其按源顺序应用。若要保留随时间变化的每个版本,请构建 Type-2 表。

在收件箱中获取最新文章

订阅我们的博客,即可在收件箱中收到最新文章。

注册

查看所有博客 slice-start id="_gatsby-scripts-1" slice-end id="_gatsby-scripts-1"