数据管道架构图:CDC、流处理与数据仓库

一张完整的数据管道架构图:从 PostgreSQL 做变更数据捕获,经过 Kafka,进入铜层、银层、金层和数据仓库,并说明每个环节该标注什么。

· 创始人兼开发者

发布于

数据管道架构图:CDC、流处理与数据仓库

数据管道总是悄无声息地出故障。仪表板显示的是昨天的数字;上游某一列改了类型,某个作业没有报错就丢掉了一些行;或者一个早已无人记得的复制槽,让生产数据库上的预写日志不断堆积,直到磁盘被占满。这些问题中的每一个,都是一个从未被画出来的环节或契约。

数据管道架构图展示数据从哪里来、如何流动、每个阶段存放在哪里、由谁在何时转换,以及大家如何知道数据是新鲜且正确的。本文以一种常见架构为例绘制这样一张图:通过 Kafka 把 PostgreSQL 的变更数据捕获(CDC)送入数据湖和数据仓库,并说明每个环节应该标注什么。

批量抽取、CDC 还是事件

从业务数据库中取出数据,常见的方法有三种:

方法 读取方式 典型新鲜度 需要注意
批量抽取 定时查询,例如 updated_at 晚于上次运行时间的行 数小时 对源库的负载;硬删除永远不会出现
基于日志的 CDC 读取数据库的事务日志 数秒到数分钟 为读取方保留的日志,以及与表结构的耦合
应用事件 服务发布领域事件,通常借助 outbox 表 数秒 需要修改代码;事件必须面向消费者来设计

基于日志的变更数据捕获(CDC)之所以在分析场景中流行,是因为它不需要修改应用、能看到删除,而且几乎不增加查询负载。它的成本在运维层面,而这些成本应该画在图上。

PostgreSQL 中基于日志的 CDC 如何工作

PostgreSQL 通过逻辑解码暴露变更,逻辑解码把预写日志(WAL)转换为行变更流。它需要 wal_level = logical、一个输出插件和一个复制槽。Debezium PostgreSQL 连接器使用 PostgreSQL 10 及以上版本自带的标准插件 pgoutput。首次启动时,它会为各表做一次一致性快照,然后流式传输每一次已提交的插入、更新和删除,默认每张表对应一个 Kafka 主题,命名为 topicPrefix.schemaName.tableName。

真正会咬人的是复制槽。PostgreSQL 文档解释说,即使没有任何连接,复制槽也会阻止删除其消费者仍需要的 WAL。如果连接器停了一个周末,主库上的 WAL 就会一直增长。max_slot_wal_keep_size 设置用于限制复制槽可以保留的 WAL 量;其默认值 -1 表示不设上限。设置上限可以保护数据库,代价是复制槽会失效,也就意味着要重新做快照。无论哪种方式,都要监控复制槽的延迟,并把复制槽画在图上。

数据湖分层与数据仓库

变更进入 Kafka 后,由 Sink 写入存储,再经过转换变得可用。Databricks 推广的奖章架构常被用来给各阶段命名:

  • 铜层保存原样到达的原始数据,并附带加载元数据,这样无需重新读取源库就能重新处理。
  • 银层保存经过清洗、去重和统一的记录:每个订单一行当前数据,类型和键保持一致。
  • 金层保存仪表板和模型读取的业务级表和聚合结果。

每一层放在哪里是一个设计决策:可以是采用 Apache Iceberg 这类开放表格式的对象存储,也可以是数据仓库本身。画出它实际所在的位置,因为成本、访问控制以及谁能查询它都由此决定。

编排与契约

从铜层到金层的转换按计划运行,或者在新数据到达时运行,由 Airflow 或 Dagster 这样的编排器管理,通常运行 dbt 中的 SQL 模型。决定一条管道是资产还是负担的,有两件事:

  • 契约。 变更事件的模式连同兼容性规则一起注册在模式注册表中,这样源表上的破坏性变更会在生产者那里大声失败,而不是在报表里悄悄出错。
  • 检查。 每一步之后都运行新鲜度、行数、唯一性和空值检查,一旦失败就在仪表板出错之前通知负责人。

示例:一家网店

网店的 PostgreSQL 数据库保存订单、支付和客户数据。Debezium 运行在 Kafka Connect 中,通过复制槽读取 WAL,并发布 shop.public.orders、shop.public.payments 和 shop.public.customers。Sink 连接器把变更事件追加到铜层表中。编排器每 15 分钟运行一次 dbt 模型来构建银层和金层,然后运行数据检查。仪表板读取金层。

商店的 Postgres 数据库通过复制槽向 Debezium 提供数据。Debezium 注册模式,并把变更事件发布到 Kafka。Sink 连接器把它们追加到铜层表;编排器从铜层构建银层和金层并运行数据检查;仪表板查询金层。

13 个组件 · 11 个连接

在 Archboard 中打开
图表内容
  • shop DB
  • Debezium
  • Kafka
  • Sink connector
  • Schema registry
  • Lake and warehouse
  • Gold: marts
  • Silver: cleaned
  • Bronze: raw changes
  • BI dashboards
  • Orchestrator: dbt
  • Data checks
  • WAL via slot
  • change events
  • register schemas
  • topic per table
  • append raw changes
  • merge, dedupe
  • aggregate
  • SQL
  • runs models
  • every 15 min
  • then checks
从运营中的 PostgreSQL 数据库到分析的数据管道:Debezium 读取预写日志,Kafka 传输变更事件,Sink 把它们落为铜层表,定时转换构建银层和金层,仪表板读取金层。

这张图的读法如下:

  • 上排,采集。 变更通过复制槽离开 PostgreSQL,在 Debezium 中变成变更事件,Debezium 会注册它们的模式;随后变更事件经由每表一个的 Kafka 主题到达 Sink 连接器。
  • 下排,存储,从右到左。 Sink 把原始变更追加到铜层。转换把它们合并进银层,再把银层聚合为金层,供仪表板查询。
  • 下方,控制。 编排器运行转换和检查;检查失败时会触发告警。
  • Markdown 块列出了复制槽和模式变更的运维规则。

需要标注什么

  • 在第一条连线上标注复制槽及其上限,以及它落后时通知谁。
  • 主题名称或命名规则,让消费者知道该订阅什么。
  • 在转换连线上标注计划和新鲜度目标,例如“每 15 分钟一次,延迟不超过 30 分钟”。
  • 每层的保留期。 铜层通常保留最久的历史,它就是你的重放缓冲区。
  • 每一层和每项检查的负责人。
  • 个人数据。 标出它们存放在哪里,以及在哪里被脱敏或丢弃;参见 GDPR 数据映射图。

常见错误

  • 从数据库到数据仓库只画一个箭头。 它隐藏了复制槽、模式,以及每一个可能丢失或延迟数据的地方。
  • 在主库上运行分析查询。 针对生产主库的批量抽取会与客户流量争抢资源;请使用 CDC 或副本,并画出用的是哪一个。
  • 没有重放路径。 如果不保留铜层,转换中的一个 bug 就意味着要重新读取源库。
  • 把原始表当作公共接口。 读取内部表变更事件的消费者会在模式变化时出错。对于面向其他团队的事件,请改为发布专门设计的事件;事件驱动架构图介绍了这一部分。
  • 只记日志的检查。 失败了却不通知任何人的测试,只是一条注释。

关于同一系统的数据库部分,请参阅数据库复制图和 ER 图示例。

在 Archboard 中构建

  1. 使用 Google 或 GitHub 登录,并新建一张图。
  2. 添加数据节点包中的一个 Postgres 节点表示源数据库,以及一个 Kafka 节点表示各主题。
  3. 添加 C4 模型节点包中的 容器 节点,分别表示 Debezium、模式注册表、Sink 连接器和仪表板。
  4. 添加一个基础节点包中的 框架,命名为 Lake and warehouse,在其中放入数据节点包中的两个 对象存储库 节点表示铜层和银层,以及一个 数据仓库 表示金层。
  5. 添加 DevOps 节点包中的一个 流水线 表示编排器,以及一个 告警 用于数据检查。控制连线画成虚线。
  6. 添加一个基础节点包中的 Markdown 块,写明复制槽和模式的规则。

这个示例共用 13 个图表节点,在 Free 套餐的限制之内。如果你用 SQL 维护源库的表结构,PostgreSQL 转 ER 图工具可以画出主题背后的表。

常见问题

CDC 比批量抽取更好吗? 就新鲜度、删除和源库负载而言,通常是的。批量方式运维更简单,如果可以接受数小时的延迟,且行从不被硬删除,批量就足够了。

做 CDC 需要 Kafka 吗? Debezium 最常运行在 Kafka Connect 上,Kafka 能提供重放能力并支持众多消费者。也有其他架构;画出你实际运行的传输方式及其保留期。

如何处理模式变更? 带兼容性规则注册模式,用新增列代替修改列,并让下游模型能够容忍新列。把注册表画出来,因为契约就在那里。

数据质量检查应该在哪里运行? 在每一层之后运行,作为编排流程的一部分,并向负责人发送告警。金层上的新鲜度检查能发现大多数静默故障。

如何让管道图保持最新? 在修改连接器和编排器配置的同一个拉取请求中修改它;参见不会过时的架构图。

免费开始 — 1 个席位,无需信用卡。

相关文章

← 返回博客

一分钟打开画布

使用 Google 或 GitHub 登录。单席位免费,团队加入后再升级。