Debezium会丢失事件吗?

是否存在这样的情况:数据库中的记录被插入、更新或删除,但 Debezium 无法从事务日志中捕获该事件并将其传播到下游消费者?

一般来说,Debezium 本身绝不会错过任何事件。如果确实如此,则被认为是一个阻碍性错误,开发团队将优先解决该错误。
Debezium 的语义是at-least-once(即可能发生重复事件,特别是在不干净的连接器关闭之后),而不是at-most-once。

话虽如此,由于操作缺陷,数据库事务日志的部分内容可能会在 Debezium 有机会捕获它们之前被丢弃。当 Debezium 连接器长时间未运行并且达到最大事务日志保留时间时,可能会发生这种情况。

大多数数据库提供某种配置参数来控制此行为:

相比之下,Postgres 处理这个问题的方式有点不同: 复制槽跟踪消费者消耗了预写日志 (WAL) 的程度。消费者必须主动确认他们消费过的最新 WAL 位置(日志序列号,LSN)。仅当 LSN 已被所有复制槽确认时,数据库才会丢弃旧的 WAL 段。这意味着,默认情况下,即使连接器停机时间延长也不会导致事件丢失。但这是有代价的:数据库保留所有未使用的 WAL 段,消耗越来越多的磁盘空间,直到连接器再次重新启动。

因此,Postgres 13 中引入了一个新的配置选项max_slot_wal_keep_size,它定义了复制槽可以保留的最大 WAL 大小(以字节为单位)。如果某个槽导致保留的 WAL 文件增长超过配置值,则较旧的段将被删除。这意味着,当配置此选项时(默认值为-1,即不确定的WAL保留大小),行为与MySQL的实例相同,并且消费者在脱离日志后将无法恢复处理。在这种情况下,通过always快照模式,您可以从新的完整初始快照开始。

一般来说,您应该从一开始就避免这种情况,并配备可观察性工具,当 Debezium 连接器长时间未运行时,例如通过查询 Kafka Connect REST API,该工具将触发警报。对于 Postgres,您还可以使用pg_current_wal_lsn()和pg_wal_lsn_diff()函数跟踪复制槽的保留 WAL 大小。