Debezium日常分享系列之:使用 Debezium 添加新表:最佳实践和陷阱
Debezium日常分享系列之:使用 Debezium 添加新表:最佳实践和陷阱
- 引言
- 场景 1
- 场景 2
- 等等!MongoDB 呢?
- 总结
- 未来展望
引言
在探索所有可能性之前,我们首先需要定义一些基本的 Debezium 概念。
Debezium 如何知道要捕获哪些表?
Debezium 提供了一组配置属性,用于决定应捕获哪些数据库、模式或表。这些过滤器的应用方式取决于源数据库的类型。
MySQL / MariaDB
- 在这些数据库中,“database” 基本上等同于 “schema”。因此,你可以通过 database.include.list 和 table.include.list 进行过滤,但没有单独的 schema 过滤器。
PostgreSQL、Oracle、SQL Server、Db2
- 一个连接器实例始终从单个数据库捕获数据。在该数据库内部,你可以通过 schema.include.list 和 table.include.list 进行过滤。
包含属性说明:
- database.include.list
- 可选的、以逗号分隔的正则表达式列表,用于匹配数据库名称。默认情况下,所有数据库都会被包含(在适用的情况下)。
- schema.include.list
- 可选的、以逗号分隔的正则表达式列表,用于匹配模式名称。默认情况下,所有非系统模式都会被包含。
- table.include.list
- 可选的、以逗号分隔的正则表达式列表,用于匹配完全限定的表标识符。每个标识符的格式为 schemaName.tableName。默认情况下,所有非系统表都会被包含。
如果您需要相反的逻辑,也有对应的排除项:
-
database.exclude.list
-
一个可选的、以逗号分隔的数据库名称排除列表。
-
schema.exclude.list
-
一个可选的、以逗号分隔的模式名称排除列表。
-
table.exclude.list
-
一个可选的、以逗号分隔的完全限定表标识符排除列表。
最终,这些属性的组合决定了Debezium将从哪些表捕获事件。请记住:您可以使用包含属性或排除属性,但不能同时使用两者。
Debezium如何获取表结构信息?
Debezium 需要知道表的模式(schema),以便能够提供有关表结构的信息。通常,Debezium 在流式传输数据变更时会学习表的模式,从而能够正确解释事件。具体的机制取决于数据库连接器:
- DDL 语句
- 大多数连接器,如 MariaDB、MySQL 和 Oracle,会从事务日志中读取 DDL 语句,解析这些语句,并更新每个表模式的内存表示。
- 元数据消息
- PostgreSQL 使用 逻辑解码 来发送关系(表)的元数据消息。Debezium 在发送表的第一个变更事件之前、每当发生模式变更,或者当复制恢复时,会接收到一个关系消息(R)。这些消息让 Debezium 知道变更属于哪个表,列的顺序,数据类型以及其他结构信息。
- JDBC 查询
- 对于如 SQL Server 和 Db2 这样的连接器,如果变更事件到达一个尚未在内存模式表示中的表,Debezium 会直接查询数据库以获取该表的模式。
现在先记住这一点,我们稍后会详细讨论它的作用。
现在,让我们退一步思考:当连接器首次启动时会发生什么?
在为一个表发送变更事件之前,Debezium 需要知道该表的结构。虽然这些信息可以在流式传输过程中通过 DDL 变更获取,但当连接器第一次启动时,DDL 语句很可能已经不在日志中了。这就是为什么 Debezium 在首次启动时需要捕获数据库模式(schema)。
另外,初始快照(initial snapshot)的主要目的是捕获数据库中当前的数据,因为当 Debezium 第一次启动时,并非所有数据都能从事务日志中获取。模式捕获是必需的,因为 Debezium 需要知道表的结构。即使你不想捕获现有数据,模式捕获也无法被禁用。不过,你可以通过 no_data 快照模式来跳过数据本身的捕获。
说到这里,你应该开始理解为什么答案是“这取决于具体情况”。
接下来,让我们看看几个你可能会遇到的常见场景。
场景 1
让我们从一个简单的场景开始:你已经配置了连接器来捕获数据库中的所有可用表。这可以通过设置相应的 *.include.list 属性来实现,或者直接不设置任何 include 和 exclude 配置——在这种情况下,Debezium 默认会捕获所有内容。
首先,在这个场景中,schema.history.internal.store.only.captured.tables.ddl 属性没有影响,因为无论如何所有表的模式都会被捕获。
如果在 Debezium 流式传输时创建了一个新表,它会捕获 DDL 并更新其内部的模式表示。当该表发生 DML 变更时,Debezium 会立即开始发送变更事件,因为表结构已经已知。
你需要检查数据库的 CDC(变更数据捕获)配置,确保新表会自动启用 CDC。这取决于连接器的具体实现。例如,在 PostgreSQL 中,这意味着 publication.autocreate.mode 设置为 all_tables(默认值)或 disabled(并且你已手动为所有表创建了发布)。
场景 2
现在假设我们处于一个场景:*.include.list 参数已设置,因此 Debezium 仅捕获数据库中可用表的一个子集。如果你保持 schema.history.internal.store.only.captured.tables.ddl 不变(默认为 false),Debezium 将在初始快照期间检索所有表的模式。
因此,如果你想开始捕获之前未捕获的表的变更,需要执行以下步骤:
- 编辑 table.include.list 属性,指定你想要捕获的表。
- 重启连接器。
- [可选] 如果你希望捕获新增表中的现有数据,可以触发增量快照(incremental snapshot)。
如果你将 schema.history.internal.store.only.captured.tables.ddl 设置为 true,过程会稍微复杂一些。在这种情况下,由于 Debezium 没有关于你想要添加的表的信息,你需要明确告诉连接器去检索它。具体步骤如下:
- 停止连接器。
- 删除由 schema.history.internal.kafka.topic 属性指定的内部数据库模式历史主题。
- 将 snapshot.mode 属性设置为 recovery(对于不支持恢复的连接器,如 PostgreSQL,可以设置为 no_data)。
- 将表添加到捕获列表中。
- 重启连接器。
基本上,这会将 Debezium 置于仅针对模式的“首次运行”模式。不会重新快照现有数据。
需要注意的是,recovery 选项应谨慎使用,因为它假设自连接器上次停止以来没有模式变更。否则,在此期间发生的一些事件可能会以错误的模式处理,导致数据损坏。
我们为 Oracle 实现了一个实验性功能,可以在 DML 操作发生时动态注册表的模式。这意味着,如果 Debezium 观察到插入、更新或删除事件,而该表的模式尚未被捕获且表匹配 include 列表,它将尝试注册当前模式并使用该模式处理事件。
等等!MongoDB 呢?
由于其无模式(schemaless)的特性,MongoDB 不需要像关系型数据库那样预先定义模式。因此,如果你想新增一个需要捕获的集合(collection),只需:
- 确保配置的 capture.scope 已包含目标集合。
- 编辑 collection.include.list,将新集合添加到捕获列表中。
总结
我们探讨了如何在不同场景下将新表添加到捕获列表,并分析了这些步骤背后的原因。希望这些内容能加深你对 Debezium 的理解,帮助你更自信地管理它。
Debezium 团队一直在努力提升项目的功能和易用性,本文正是这一持续努力的一部分。
未来展望
最理想的功能往往是那些无需解释的“开箱即用”功能。为此,我们正在考虑添加一个内置的信号(signal)操作,用于触发特定表的模式刷新。这将使新增表到捕获列表的过程更加流畅和简单。