这篇文章最初发表在Bolt Labs工程博客

传统上,MySQL被用于支持大多数后端服务螺栓.我们已经设计了模式,它们被分割到不同的MySQL集群中。每个MySQL集群包含一个数据子集,由一个主节点和多个复制节点组成。

数据持久化到数据库后,我们使用开云体育电动老虎机开云体育官方注册网址Debezium MySQL连接器捕获数据更改事件然后寄给卡夫卡这为我们提供了一种简单可靠的方式,可以在后端微服务之间进行更改通信。

维特斯在博尔特

在过去的几年里,Bolt有了很大的发展,写入MySQL的数据量也有了很大的增长。手动数据库分片开云体育电动老虎机已经成为一个非常昂贵和持久的过程,容易出错。所以我们开始评估更可扩展的数据库,其中之一就是开云体育电动老虎机维塔斯.Vitess是一个基于MySQL的开源数据库集群系开云体育电动老虎机统,并为其提供横向可伸缩性。它起源于YouTube并经过实战测试,后来被开源,被Slack、Github、京东等公司用于支持后端存储。它结合了重要的MySQL特性和NoSQL数据库的可伸缩性。开云体育电动老虎机

Vitess提供的最重要的功能之一是其内置的分片。它允许数据库以一种对后端应用开云体育电动老虎机程序逻辑透明的方式添加新的碎片来水平增长。对于您的应用程序,Vitess看起来像一个巨大的单个数据库,但实际上数据在幕后被划分为多个物理碎片。开云体育电动老虎机对于任何表,可以选择任意列作为切分键,所有的插入和更新都将无缝地由Vitess本身定向到适当的切分。

图1下面说明后端服务如何与Vitess交互。在高层次上,服务通过负载均衡器连接到无状态VTGate实例。每个VTGate在其内存中缓存了Vitess集群的拓扑结构,并将查询重定向到碎片中的正确的分片和正确的VTTablet(及其底层MySQL实例)。关于VTTablet的更多信息写在下面。

图1。维塔斯的体系结构。参考:https://www.planetscale.com/vitess

Vitess提供的其他有用功能包括:

  • 故障转移(也称为重养育)对客户端来说是简单和透明的。客户端只与VTGate通信,VTGate透明地负责新主服务器的故障转移和服务发现。

  • 它会自动重写可能导致数据库性能下降的“有问题的”查询。开云体育电动老虎机

  • 它有一个缓存机制,可以防止重复查询同时到达底层MySQL数据库。开云体育电动老虎机只有一个查询将到达数据库,其结果将被缓存并返回以回答重复的查开云体育电动老虎机询。

  • 它有自己的连接池,消除了MySQL连接的高内存开销。因此,它可以轻松地同时处理数千个连接。

  • 可以配置连接超时和事务超时。

  • 它有最小的停机时间重新切分操作。

  • 下游CDC应用程序可以使用它的VStream特性从Vitess读取更改事件。

流媒体Vitess选项

捕获数据更改并将其发布到Apache Kafka的能力是Bolt采用Vitess的要求之一。我们考虑过几种不同的选择。

选项1:使用Debezium M开云体育官方注册网址ySQL连接器

应用程序连接到Vitess VTGate发送查询。VTGate支持MySQL协议,并提供SQL解析器。您可以使用任何MySQL客户端(例如JDBC)连接到VTGate,它将您的查询重定向到正确的分片,并将结果返回给您的客户端。

然而,VTGate并不等于一个MySQL实例,它是各种MySQL实例的无状态代理。为了让MySQL连接器接收更改事件,Debezium MySQL连接器需要连接到一个真正的MySQL实例。开云体育官方注册网址更明显的是,VTGate也有一些已知的兼容性问题,这使得连接到VTGate不同于MySQL。

另一种选择是使用Debezium MySQL连接器直接连接开云体育官方注册网址到不同分片的底层MySQL实例。它有它的优点和缺点。

一个优点是,对于一个未分片的键空间(Vitess对数据库的术语),MySQL连接器可以继续正确工作,我们不需要包括额外的逻辑或特定的实现。开云体育电动老虎机它应该可以正常工作。

最大的缺点之一是重新分片操作将变得更加复杂。例如,原始MySQL实例的GTID在重新分片时会改变,而MySQL连接器依赖于GTID才能正确工作。我们还认为,让MySQL连接器直接连接到每个底层MySQL实例违背了Vitess操作简单的目的,因为每次重分片都必须添加(或删除)一个新的连接器。更不用说这样的操作会导致Kafka代理内部的数据复制。

选项2:使用JDBC源连接器

我们还考虑过使用JDBC源连接器.它允许从任何支持JDBC驱动程序的关系数据库中获取数据到Kafka中。开云体育电动老虎机因此,它与Vitess VTGate兼容。它也有它的优点和缺点。

优点:

  • 它与VTGate兼容。

  • 它能更好地处理Vitess重分片操作。在重分片操作期间,读数据被简单地自动重定向(由VTGate)到目标分片。它不会产生任何副本或丢失任何数据。

缺点:

  • 它是基于轮询的,这意味着连接器以定义的间隔(通常每隔几秒)轮询数据库以获取新的更改事件。开云体育电动老虎机这意味着与Debezium MySQL连接器相比,我们将有更高的延迟。开云体育官方注册网址

  • 它的偏移量由表的增量主键或表的时间戳列之一管理。如果使用时间戳列进行偏移,则必须为每个表创建时间戳列的二级索引。这为我们的后端服务增加了更多约束。如果使用增量主键,就会错过行更新的更改事件,因为根本没有更新主键。

  • JDBC连接器创建的主题名称不包括表的模式名称。使用topic.prefix连接器配置意味着每个模式有一个连接器。在Bolt中,我们有大量的模式,这意味着我们需要创建大量的JDBC源连接器。

  • 在Bolt,我们的下游应用程序已经设置为使用Debezium的数据格式和主题命名约定,例如,我们需要将下游应用程序的解码逻辑更开云体育官方注册网址改为新的数据格式。

  • 不捕获行删除。

选项3:使用VStream gRPC

VTGate公开了一个名为VStream的gRPC服务。它是一个服务器端流服务。任何gRPC客户端都可以订阅VStream服务从底层MySQL实例获取连续的更改事件流。VStream发出的更改事件具有与底层MySQL实例的MySQL二进制日志类似的信息。单个VStream甚至可以为给定的密钥空间订阅多个分片,使其成为构建CDC工具的非常方便的API。

幕后,如图所示图2, VStream从多个中读取更改事件VTTablets,每个碎片一个VTTablet。因此,对于一个给定的分片,它不会从多个vttablet发送副本。每个VTTablet都是其MySQL实例的代理。典型的拓扑包括一个主VTTablet及其对应的MySQL实例,以及多个副本VTTablet,每个副本VTTablet都是其自己的副本MySQL实例的代理。VTTablet从其底层MySQL实例获取变更事件,并将变更事件发送回VTGate, VTGate又将变更事件发送回VStream的gRPC客户端。

客户端订阅VStream服务时,可以指定VGTID和VGTID平板电脑类型(如。副本).VGTID告诉VStream开始发送变更事件的位置。本质上,VGTID包含一个元组列表(键空间、分片、分片GTID)。Tablet Type告诉我们从每个分片中的哪个MySQL实例(主或副本)中读取更改事件。

图2。VStream架构。参考:https://vitess.io/docs/concepts/vstream

使用VStream gRPC的一些优点是:

  • 这是一种从Vitess接收变更事件的简单方法。Vitess的书中也有推荐文档使用VStream构建下游CDC流程。

  • VTGate隐藏了连接到各种源MySQL实例的复杂性。

  • 它具有较低的延迟,因为更改事件一旦发生就会流到客户端。

  • 更改事件不仅包括插入和更新,还包括删除。

  • 可能最大的优点之一是更改事件包含每个表的模式。因此,您不必担心提前获取每个表的模式(例如,通过解析ddl或查询表的定义)。

  • 更改事件包含了VGTID, CDC进程可以存储VGTID,并将其用作下次重新启动CDC进程的偏移量。

  • 同样重要的是,VStream的设计可以很好地与Vitess的操作,如重新切分而且移动表

也有一些缺点:

  • 尽管它包括表模式,但仍然缺少一些重要的信息。例如,枚举而且列类型还没有提供所有允许的值。不过,这应该在下一个主要版本(Vitess 9)中得到修复。

  • 由于VStream是一个gRPC服务,我们不能开箱即用地使用Debezium MySQL连接器。开云体育官方注册网址但是,用其他语言实现gRPC客户机非常简单。

综合考虑,我们决定使用VStream gRPC从Vitess中捕获变更事件,并基于Debezium的所有最佳实践实现我们的Vitess连接器。开云体育官方注册网址

Vitess连接器深潜和开源

在我们决定实现我们的Vitess连接器之后,我们开始研究各种Debezium源连接器(MySQL, Postgres, SQLServer)的实现细节,以借鉴一些想法。开云体育官方注册网址几乎所有这些都是使用公共连接器开发框架实现的。所以很明显,我们应该在它的基础上开发Vitess连接器。考虑到我们是MySql连接器非常活跃的用户,我们受益于它的开源,因为它允许我们为它贡献我们自己失去的东西。所以我们决定回馈社区,在Debezium框架下开源Vitess源连接器代码库。开云体育官方注册网址请随时在开云体育官方注册网址Debezium连接器Vitess.我们欢迎并重视任何贡献。

在高层次上,如你所见,连接器实例是在Kafka Connect工人中创建的。在撰写本文时,您有两个选项来配置连接器从Vitess读取:

选项1(推荐):

图3,每个连接器从特定密钥空间中的所有碎片捕获更改事件。如果密钥空间没有分片,连接器仍然可以从密钥空间中唯一的分片捕获更改事件。当连接器第一次启动时,它从密钥空间中所有碎片的当前VGTID位置读取。因为它订阅了所有的分片,所以它不断地从所有的分片中捕获变更事件,并将它们发送给Kafka。它自动支持Vitess Reshard操作,没有数据丢失,也没有复制。

图3。每个连接器订阅特定密钥空间的所有碎片

选项2:

图4,每个连接器实例从特定的密钥空间/碎片对捕获更改事件。连接器实例从VTCtld gRPC(另一个Vitess组件)获取密钥空间/分片对的初始(当前)VGTID位置。每个连接器实例,独立地使用它获得的VGTID订阅VStream gRPC,并不断从VStream捕获更改事件,并将它们发送到Kafka。为了支持Vitess Reshard操作,您需要更多的手动操作。

图4。每个连接器订阅特定密钥空间的一个碎片

在内部,每个连接器任务使用gRPC线程不断地从VStream接收更改事件,并将事件放入内部阻塞队列。连接器任务线程轮询队列中的事件并将它们发送给Kafka,如图所示图5

图5。每个连接器任务内部是如何工作的

复制的挑战

当我们实现Vitess连接器并深入挖掘Vitess时,我们也意识到一些挑战。

维塔斯Reshard

当连接器配置为订阅给定密钥空间的所有碎片时,Vitess连接器支持Vitess Reshard操作。VStream发送一个VGTID,其中包含所有碎片的GTID。Vitess Resharding对用户是透明的。一旦完成,Vitess将发送新碎片的VGTID。因此,连接器将使用重新分片后的新VGTID。但是,您需要确保连接器在重新分片操作发生时处于启动和运行状态。特别是在删除旧的分片之前,请检查连接器的偏移主题是否有新的VGTID。这是因为如果旧的碎片被删除,VStream将无法从旧的碎片中识别VGTID。

如果您决定订阅每个连接器一个分片,则该连接器不提供Vitess重分片的开箱即用支持。支持重分片的一种手动解决方法是为每个目标分片创建一个新的连接器。的一个新连接器商务/ -80碎片和另一个新的连接器商务/ 80 -碎片。请记住,因为它们是新的连接器,默认情况下将创建新的主题,但是,您可以使用开云体育官方注册网址Debezium逻辑主题路由器将记录路由到相同的Kafka主题。

抵消管理

VStream在其响应中包含一个VGTID事件。我们将VGTID保存为Kafka偏移量主题中的偏移量,因此当连接器重新启动时,我们可以从保存的VGTID开始。但是,在极少数情况下,当事务包含大量行的时候,VStream会将更改事件批量处理为多个响应,并且只有最后一个响应具有VGTID。在这种情况下,我们并没有收到的每个更改事件的VGTID。我们有几个选项来解决这个特殊的问题:

  • 我们可以在内存中缓冲所有更改事件,并等待包含VGTID的最后一个响应到达。因此,所有事件都将有正确的VGTID与之关联。一些缺点是,在事件发送到Kafka之前,我们会有更高的延迟。此外,由于缓冲,内存使用可能会增加很多。缓冲还增加了逻辑的复杂性。我们也无法控制VStream发送给我们的事件的数量。

  • 我们可以使用我们拥有的最新的VGTID,这是来自之前VStream响应的VGTID。如果连接器在处理如此大的事务时失败并重新启动,它将从前一个VStream响应的VGTID重新启动,从而重新处理一些事件。因此,它具有至少一次事件传递语义,并且它期望下游是幂等的。由于大多数事务都不够大,大多数VStream响应将在响应中包含VGTID,因此具有副本的可能性很低。最后,我们选择了这种方法,因为它保证了至少一次交付,并且设计简单。

模式管理

VStream的回复还包括事件。这是一个特殊事件,它包含受影响的表的模式。例如,假设我们有两张表,一个而且B.如果我们向表中插入几行一个,事件将只包含表一个的模式。VStream足够智能,只包括事件。例如,当VStream客户端重新连接时,或者当表的模式发生更改时。

VStream的旧版本只包含列类型(例如。整数Varchar),没有其他信息,例如该列是否是主键,该列是否有默认值,小数类型的规模和精度,枚举类型允许的值,等等。

VStream的新版本(Vitess 8)开始在每列上包含更多信息。这将帮助连接器更准确地反序列化某些类型,并在发送到Kafka的更改事件中拥有更精确的模式。

未来发展工作

  • 我们可以使用VStream的API从最新的VGTID位置开始流,而不是从VTCtld gRPC获得初始的VGTID位置。这样做将消除对VTCtld的依赖。

  • 我们还不支持从变更事件中自动提取主键。目前,默认情况下,所有发送到Kafka的更改事件都有如钥匙,除非message.key.columns指定连接器配置。Vitess最近在VStream FIELD事件中添加了每个列的标志,这允许我们很快实现这个功能。

  • 增加对初始快照的支持,以便在流更改之前捕获所有现有数据。

总结

MySQL已经被用于Bolt的大部分后端服务。由于数据量和操作复杂性的显著增长,Bolt开始评估Vitess的可伸缩性和内置功能,如重新分片。

为了从Vitess中捕获数据更改,就像我们使用Debezium MySQL Connector所做的那样,我们考虑了几个选项。开云体育官方注册网址最后,我们基于通用的Debezium连接器框架实现了自己的Vitess连接器。开云体育官方注册网址在实现Vitess连接器时,我们遇到了一些挑战。例如,支持Vitess重分片操作、偏移量管理和模式管理。我们讨论了应对挑战的方法,以及我们提出的解决方案。

我们也收到了来自多个社区对这个项目的兴趣,我们决定开源维塔斯的连接器在Debezium的开云体育官方注册网址保护伞下。请随时了解更多信息,我们欢迎并重视任何贡献。

Kewei商

Kewei是Bolt的高级软件工程师,他主要专注于Kafka、Debezium、变更数据捕获、数据仓库和创建事件驱动系统。开云体育官方注册网址

Ruslan Gibaiev

Ruslan是Bolt的流媒体平台负责人。他喜欢构建分布式系统,喜欢实时数据而不是批处理。


关于Debe开云体育官方注册网址zium

开云体育官方注册网址Debezium是一个开源的分布式平台,它将现有数据库转换为事件流,因此应用程序几乎可以立即看到并响应数据库中提交的每一个行级更改。开云体育电动老虎机开云体育官方注册网址Debezium是建立在卡夫卡并提供卡夫卡连接监控特定数据库管理系统的兼容连接器。开云体育电动老虎机开云体育官方注册网址Debezium在Kafka日志中记录了数据更改的历史,所以你的应用程序可以在任何时候停止和重新启动,并且可以很容易地使用它没有运行时错过的所有事件,确保所有事件都被正确和完整地处理。开云体育官方注册网址Debezium是开源Apache许可证,版本2.0

参与

我们希望您觉得Debezium有趣开云体育官方注册网址且有用,并愿意尝试一下。在Twitter上关注我们@开云体育官方注册网址debezium在Zulip上和我们聊天,或加入我们的邮件列表与社区对话。所有的代码都是开源的GitHub上,因此在本地构建代码并帮助我们改进现有连接器并添加更多连接器。如果您发现了问题或对我们如何改进Debezium有想法,请告诉我们开云体育官方注册网址记录问题

Baidu
map