Flink SQL 秘密:掌握变更日志事件无序的艺术

简介

Alice 是一名数据工程师,负责公司的实时数据处理。她发现Flink SQL有时会产生更新(关于键)事件。但是,在 Flink 的早期版本中,这些事件无法直接写入 Kafka,因为 Kafka 本质上是一个仅追加的消息系统。幸运的是,Flink 社区在更高版本中发布了 Connectorupsert-kafka,支持写入更新事件。后来她发现Flink SQL作业readupsert-kafkaevents进行join操作时偶尔会出现错误。这让她对Flink SQL的可靠性产生了怀疑。她向社区报告了该问题,确认是变更日志事件乱序问题,随后在新版本中得到了解决。终于,她又可以继续愉快地使用 Flink SQL 了。从 Alice 使用 Flink SQL 的经历中我们可以了解到,实时数据处理并不总是顺利和直接的。为了让 Flink SQL 更容易理解,本文试图解开 Flink SQL 中变更日志事件乱序问题的谜团。我们首先介绍 Flink SQL 中的changelog,然后演示changelog事件乱序问题及其解决方案。最后,我们将针对这个问题提出最佳实践,以帮助您更好地理解和使用 Flink SQL 进行实时数据处理。

Flink SQL 中的 ChangelogChangelog 并不是 Flink SQL 发明的新概念。在关系数据库世界中,MySQL使用众所周知的binlog(二进制日志)来记录数据库中的所有修改操作,包括INSERT、UPDATE和DELETE操作。同样,Flink SQL 中的changelog 也用于记录这些数据变化,以实现增量数据处理。在 MySQL 中,binlog 可以用于数据的备份恢复、同步和复制。通过读取并解析binlog中的操作记录,可以实现增量数据的同步和复制。变更数据捕获(CDC)是一种常用的数据同步技术,它监视数据库中的数据变化并将这些变化转换​​为事件流进行实时处理。 CDC工具可用于将关系数据库中的数据变化实时传输到其他系统或数据仓库,以支持实时分析和报告。常见的CDC工具包括Debezium和Maxwell。通过 FLINK-15331 添加的 Flink CDC 支持,允许与外部系统的 CDC 数据实时集成,并通过 Flink 实现实时数据同步和分析。 在 Flink SQL 中生成和处理 Changelog 事件。虽然前面提到的 binlog 和 CDC 是与 Flink 集成的外部 Changelog 数据源,但 Flink SQL 内部也会生成 Changelog 数据。为了区分事件是否是更新事件,我们将仅包含 INSERT 类型事件的变更日志称为附加流,而另外包含其他类型(例如 UPDATE)事件的变更日志称为更新流。

Flink 中的一些操作(例如组聚合、去重)会产生更新事件。生成更新事件的运算符通常会维护状态,我们通常将它们称为有状态运算符。值得注意的是,并非所有有状态运算符都支持将更新流作为输入进行处理。例如,窗口聚合和间隔连接目前还不支持更新流作为输入。

熟悉Debezium数据格式(或数据库binlog解析)的用户可能想知道为什么Flink不使用复合UPDATE事件类型(就像数据库所做的那样),既包含UPDATE_BEFORE(UB)又包含UPDATE_AFTER(UA)并且更紧凑。事实上,我们在设计和实现 Flink 的回缩机制时就仔细评估了这个选项。复合 UPDATE 事件在某些场景下确实更加紧凑,可以解决特定问题(例如 FLINK-9528),但我们选择不使用它的原因主要是以下两个方面:拆分事件无论事件类型如何,其事件结构都是相同的(仅 RowKind 不同),这使得序列化更简单。如果使用复合 UPDATE 事件,则事件要么是异构的,要么 INSERT/DELETE 也被建模为 UPDATE 事件(例如,INSERT 事件仅具有 UA,DELETE 事件仅具有 UB)。在分布式环境中,经常涉及数据混洗操作(例如,联接、聚合)。即使使用复合 UPDATE 事件,在某些场景中进行混洗时,它们仍然必须拆分为单独的 DELETE 和 INSERT 事件。

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。更多免费资源在http://www.gitweixin.com/?p=2627