变更数据捕获是一个热门话题。Debezium 的目标是让多种 DBMS 的变更数据捕获变得容易,但不可否认,我们仍然是一个年轻的开源项目,到目前为止,我们只发布了一个 MySQL 连接器,还有一个 MongoDB 连接器 即将推出。因此,看到其他人如何使用和实现变更数据捕获非常棒。在这篇文章中,我们将回顾 Yelp 的方法,并看看它与 Debezium 的 MySQL 连接器有何惊人的相似之处。
Yelp 的数据流
Yelp 工程博客 最近开始了一系列文章,介绍其实时数据流基础设施。该第一篇文章提供了很好的介绍,解释了如何从单体架构迁移到面向服务的架构提高了生产力,但也使得处理分散在 100 个服务中的数据变得更具挑战性。现在就花时间阅读它绝对值得。
正如 Justin 在文章中所写,有几个原因促使他们创建了自己的实时数据流管道:
-
确保跨服务数据始终保持一致始终是一项艰巨的任务,尤其是在事物可能出错并且确实会出错时。跨服务的事务在某些情况下可能很有用,但它们并不简单,成本高昂,并且可能导致请求放大,即一个服务调用另一个服务,而另一个服务又与其他两个服务协调,等等。
-
更新多个后端服务中数据的服务会遇到双写问题,即在一个后端服务更新后但在另一个服务更新之前发生故障,这总是会导致难以追踪和纠正的数据不一致。
-
跨多个服务组合和集成数据也可能很困难且成本高昂,但当数据持续变化时,情况会更糟。一种方法是使用批量 API,但这些 API 的创建可能成本过高,可能导致不一致,并且当服务需要不断接收数据永无止境的更新时,会带来真正的可伸缩性问题。
Yelp 的实时数据管道将数据更改记录在完全排序的分布式日志中,以便下游消费者可以按完全相同的顺序接收和处理相同的更改。服务可以消费其他服务所做的更改,从而在没有显式服务间通信的情况下保持同步。该系统使用了 Kafka 的事件日志、一个名为 MySQLStreamer 的自研系统来捕获 MySQL 表的已提交更改、Avro 作为消息格式和模式,以及一个自定义的 Schematizer 服务,该服务跟踪消费者并强制执行用于每个 Kafka 主题消息的 Avro 模式。
Yelp 如何捕获 MySQL 更改
对于 Debezium 来说,也许最有趣的是 Yelp 如何捕获其 MySQL 数据库中的已提交更改并将其写入 Kafka 主题。该系列中的第二篇文章详细介绍了他们的 MySQLStreamer 进程,该进程读取 MySQL 二进制日志并持续处理日志中出现的 DDL 语句和 DML 操作,生成相应的插入、更新、删除和刷新事件,并将这些事件消息写入每个 MySQL 表的单独 Kafka 主题。我们之前提到过,由 DML 操作产生的 MySQL 行级 binlog 事件不包含列的完整定义,因此知道每个事件中的列的含义需要处理 binlog 中也出现的 DDL 语句。Yelp 使用一个单独的 MySQL 实例,称为模式跟踪数据库,它像一个 MySQL slave 一样工作,只应用从 binlog 中读取的 DDL 语句。这种技术使 Yelp 的 MySQLStreamer 系统能够在处理事件的 binlog 点了解数据库模式的状态及其表结构。这非常有趣,因为它使用了 MySQL 引擎来处理 DDL 解析。
Yelp 的 MySQLStreamer 进程使用另一个 MySQL 数据库来跟踪内部状态,描述其在 binlog 中的位置、哪些事件已成功发布到 Kafka,以及(由于每个副本的 binlog 位置不同)关于每个事务的副本无关信息。后者信息类似于 MySQL GTID,尽管 Yelp 使用不支持 GTID 的早期 MySQL 版本。
当然,对于长期存在的数据库必须给予特别考虑。MySQL 的二进制日志是有限的,并且不包含数据库的全部历史记录,因此 Yelp 的 MySQLStreamer 进程通过启动另一个干净的 MySQL 副本(它将使用内置的 MySQL 复制机制和MySQL 黑洞数据库引擎)来获取主服务器的一致快照,并确保副本的 binlog 中记录了所有活动,而副本实际上不存储任何数据,从而引导旧数据库的更改数据捕获过程。
Yelp 的 MySQLStreamer 机制在利用 MySQL 和多个额外数据库从 MySQL 数据库捕获更改并将其写入 Kafka 主题方面非常巧妙。当然,缺点是这样做会增加系统的操作复杂性。
类似的目的,类似的方法
Debezium 是一个开源项目,正在为各种 DBMS 构建更改数据捕获。与 Yelp 的 MySQLStreamer 类似,Debezium 的MySQL 连接器可以持续捕获 MySQL 数据库行的已提交更改,并将这些事件记录在每个表的单独 Kafka 主题中。首次启动时,Debezium 的 MySQL 连接器可以执行初始一致性快照,然后开始读取 MySQL binlog。它使用 binlog 中出现的 DDL 和 DML 操作,直接解析并使用 DDL 语句来了解每个表的结构更改以及每个插入、更新和删除 binlog 事件的映射。每个写入 Kafka 的更改事件都包含有关源 MySQL 服务器及其 binlog 位置的信息,以及受影响行的之前和/或之后的状态。
然而,与 Yelp 的 MySQLStreamer 不同,Debezium MySQL 连接器不需要或使用额外的 MySQL 数据库来解析 DDL 或存储连接器的状态。相反,Debezium 构建在 Kafka Connect 之上,这是一个新的 Kafka 库,提供了从外部系统可靠拉取数据、将其推送到 Kafka 主题以及跟踪已处理数据的大部分通用功能。Kafka Connect 将此状态存储在 Kafka 本身中,从而简化了操作足迹。然后,Debezium 的 MySQL 连接器可以专注于在需要时执行一致性快照、读取 binlog 以及将 binlog 事件转换为有用的更改事件的细节。
Yelp 的实时数据管道使用了自定义的 Avro Schema Registry,并使用这些 Avro Schema 将每个事件编码为紧凑的二进制表示,同时保留有关事件结构的元数据。使用 Debezium 也可以做到这一点:只需将Confluent 的 Schema Registry作为服务运行,然后配置 Kafka Connect 工作程序使用Avro 转换器。当转换器序列化每个事件时,它会查看连接器定义的结构,当该结构发生更改时,它会生成一个更新的 Avro Schema 并将其注册到 Schema Registry。然后,新的 Avro Schema 将用于将事件(以及其他结构相同的事件)编码为写入 Kafka 的紧凑二进制形式。当然,消费者也使用相同的 Avro 转换器,以便在反序列化事件时,转换器会在需要它不知道的 Avro Schema 时与 Schema Registry 进行协调。因此,事件以紧凑的方式存储,而事件的内容和元数据保持可用,同时 Schema Registry 捕获并维护每个表随着时间演变的 Avro Schema 的历史记录。
使用 Debezium 捕获 MySQL 的更改
如果您对 MySQL(或其他任何 DBMS)的更改数据捕获感兴趣,请通过我们的教程尝试 Debezium,该教程将引导您启动 Kafka、Kafka Connect 和 Debezium 的 MySQL 连接器,以确切了解更改数据事件的外观以及如何使用它们。最重要的是,它是开源的,并且拥有不断增长的开发者社区,他们受益于建立在最近创建的 Kafka Connect 框架之上。我们的 MySQL 连接器现在可用,但我们正在为其他 DBMS 开发连接器。特别是,我们即将发布的 0.3 版本将包含我们的MongoDB 连接器,0.4 版本将包含 PostgreSQL 和/或 Oracle 的连接器。
更正:本文之前的版本错误地指出 Yelp 使用了支持 GTID 的 MySQL 版本,而实际上他们使用的是不支持 MySQL GTID 的版本。本文已得到更正,作者对此表示歉意。
关于 Debezium
Debezium 是一个开源的分布式平台,可以将现有数据库转变为事件流,使应用程序能够几乎即时地看到并响应数据库中已提交的每个行级更改。Debezium 构建在 Kafka 之上,并提供了 Kafka Connect 兼容的连接器,用于监控特定的数据库管理系统。Debezium 将数据更改的历史记录在 Kafka 日志中,这样您的应用程序可以随时停止和重新启动,并可以轻松地消费在未运行时错过的所有事件,确保所有事件都被正确且完整地处理。Debezium 在 Apache 许可证 2.0 下是 开源 的。