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

从历史上看,MySQL实际上是WePay微服务的首选数据库。开云体育电动老虎机随着WePay规模的扩大,写入一些微服务数据库的大量数据要求我们在分片MySQL(即。开云体育电动老虎机维塔斯),并切换到本地分片的NoSQL数据库。开云体育电动老虎机经过一系列评估后,我们选择了Cassandra,这是一个NoSQL数据库,主要是因为它的高可用性、水平可伸缩性和处理高写开云体育电动老虎机吞吐量的能力。

批处理ETL选项

在将Cassandra引入我们的基础设施之后,我们的下一个挑战是找出一种方法来公开Cassandra中的数据BigQuery我们的数据仓库,用于分析和报告。我们很快建立了一个气流而且操作符执行全负载。这显然是不可伸缩的,因为它在每次加载时都会重写整个数据库。开云体育电动老虎机为了扩展管道,我们评估了两种增量负载方法,但它们都有各自的缺点:

  1. 范围查询。这是一种常见的ETL方法,其中通过定期(如每小时或每天)的范围查询提取数据。有人熟悉吗卡桑德拉数据建模很快就会意识到这种方法是多么不现实。Cassandra表需要建模,以优化生产中使用的查询模式。在大多数情况下,为分析添加此查询模式意味着用不同的集群键克隆表。RDBMS人员可能建议使用二级索引来支持这种查询模式,但是二级索引在Cassandra是本地的因此,这种方法本身就会带来性能和扩展问题。

  2. 处理未合并的sstable。sstable是Cassandra的不可变存储文件。卡桑德拉提供了一个sstabledump将SSTable内容转换为人类可读的JSON的CLI命令。然而,Cassandra是建立在概念之上的LSM (log structured Merge)树,意味着sstable会定期合并到新的压缩文件中。根据压缩策略,在带外检测未合并的SSTable文件可能具有挑战性(我们后来了解到增量备份Cassandra中只备份未压缩的sstable的特性;所以这种方法也同样有效。)

考虑到这些挑战,建立并运营了一个MySQL的流式数据管道,我们开始为卡桑德拉探索流媒体选择。

流选项

Double-Writing

图像显示作家发送两个不同的写入

这个想法是每次在Cassandra上执行写操作时都要发布到Kafka。这种双重写入可以通过内置触发器或客户端的自定义包装器来执行。这种方法存在性能问题。首先,由于我们现在需要向两个系统而不是一个系统写入数据,写入延迟增加了。更重要的是,当对一个系统的写入由于超时而失败时,写入是否成功是不确定的。为了保证两个系统上的数据一致性,我们必须实现分布式事务,但是为了达成共识的多次往返将增加延迟并进一步降低吞吐量。这违背了高写吞吐量数据库的目的。开云体育电动老虎机

Kafka作为事件源

图像显示写入发送到Kafka,然后下游DB

这个想法是写信给卡夫卡,而不是直接写信给卡桑德拉;然后通过消费卡夫卡的事件将写应用到卡桑德拉。事件来源是目前非常流行的方法。但是,如果您已经有了直接写入Cassandra的现有服务,则需要更改应用程序代码并进行重要的迁移。这种方法也违反了“读己之所写”一致性:如果一个进程执行写操作,那么执行后续读操作的同一进程必须观察写操作的效果。由于写操作是通过Kafka路由的,所以在发出写操作和应用写操作之间会有一个延迟;在此期间,对Cassandra的读取将导致陈旧的数据。这可能会导致不可预见的生产问题。

解析提交日志

图片显示提交日志发送到Kafka

Cassandra介绍了变更数据捕获(CDC)特性在3.0中公开其提交日志。提交日志是Cassandra中的提前写入日志,旨在在机器崩溃时提供持久性。它们通常在冲洗时被丢弃。启用CDC后,它们会在刷新时转移到本地CDC目录,然后Cassandra节点上的其他进程可以读取该目录。这允许我们使用与MySQL流管道中相同的CDC机制。它将生产操作从分析中分离出来,因此不需要应用工程师进行额外的工作。

最终,在考虑了吞吐量、一致性和关注点分离之后,最后一个选项——解析提交日志——成为了最有力的竞争者。

深潜日志

除了公开提交日志外,Cassandra还提供CommitLogReader而且CommitLogReadHandler类来帮助反序列化日志。看起来困难的工作已经完成,剩下的就是应用转换——将反序列化的表示转换为Avro记录并发布到Kafka。然而,当我们深入研究CDC特性和Cassandra本身的实现时,我们意识到还有许多新的挑战。

延迟处理

提交日志只有在CDC目录满时才会到达CDC目录,在这种情况下,它将被刷新/丢弃。这意味着在记录事件和捕获事件之间存在延迟。如果很少执行写操作,甚至不执行写操作,那么事件捕获的延迟可以任意长。

空间管理

在MySQL中,您可以设置二进制日志保留,这样日志将在配置的保留期限后自动删除。然而在Cassandra中却没有这样的选择。一旦提交日志被传输到CDC目录,必须在处理后清理提交日志。如果CDC目录的可用磁盘空间超过给定的阈值,则将拒绝对数据库的进一步写入。开云体育电动老虎机

重复的事件

单个Cassandra节点上的提交日志不反映对集群的所有写入;它们只反映对节点的写操作。这就需要在所有节点上处理提交日志。但是当复制因子为N时,每个事件的N个副本被发送到下游。

无序的事件

对单个Cassandra节点的写入在到达时被连续记录。但是,这些事件在发布时可能会出现紊乱。这些事件的下游消费者必须了解事件时间并实现与上次写入获胜逻辑类似的逻辑Cassandra的读路径才能得到正确的结果。

带外架构更改

表的架构更改通过流言协议并且不会记录在提交日志中。因此,只能在尽最大努力的基础上检测模式的更改。

不完整的行数据

Cassandra不执行先读后写,因此更改事件不会捕获每个列的状态,它们只捕获已修改列的状态。这使得更改事件的用处不如整行可用时大。

一旦我们对Cassandra提交日志有了深刻的理解,我们根据给定的约束重新评估了我们的需求,以便设计一个最小可行的基础设施

最低可行基础设施

最小可行产品我们的理念是,我们想要设计一个具有最小功能和需求集的数据管道,以满足我们的直接客户。对于Cassandra CDC,这意味着:

  • 生产数据库的运行状况和开云体育电动老虎机性能不应因引入CDC而受到负面影响;缓慢的操作和系统停机时间比分析管道的延迟要昂贵得多

  • 在我们的数据仓库中查询Cassandra表应该与查询生产数据库的结果相匹配(排除延迟);开云体育电动老虎机有了这些标准,我们开始头脑风暴寻找解决方案,最终提出了三种方法:

无状态流处理

这个解决方案受到Datastax的启发高级复制博客文章.其思想是在每个Cassandra节点上部署一个代理来处理本地提交日志。每个代理都被认为是基于分区键的写操作子集的“主代理”,这样每个事件都只有一个主代理。然后在CDC期间,为了避免重复事件,每个代理只有在它是事件的主代理时才向Kafka发送事件。为了处理最终的一致性,每个代理会在事件到达时将它们排序到每个表的时间切片窗口中(但不会立即发布它们);当一个窗口过期时,该窗口中的事件将被散列,并将散列与其他节点进行比较。如果不匹配,则从不一致的节点获取数据,以便通过最后写入获胜来解析正确的值。最后,该窗口中的修正事件将被发送到Kafka。任何超出时间切片窗口的乱序事件都必须记录到一个乱序文件中并单独处理。由于重复数据删除和排序是在内存中完成的,代理故障转移导致的数据丢失、OOM问题影响生产数据库以及该实现的整体复杂性使我们无法进一步研究它。开云体育电动老虎机

有状态流处理

这个解决方案是功能最丰富的。其思想是每个Cassandra节点上的代理将处理提交日志并将事件发布到Kafka,而无需重复数据删除和排序。然后,流处理引擎将使用这些原始事件并完成繁重的工作(比如用缓存过滤掉重复的事件,用事件时间窗口管理事件顺序,通过在状态存储上执行读前写来捕获未修改的列的状态),然后将这些派生事件发布到单独的Kafka主题。最后,KCBQ将用于消费来自该主题的事件并将它们上传到BigQuery。这种方法很有吸引力,因为它一般地解决了问题——任何人都可以订阅后一个Kafka主题,而不需要自己处理重复数据删除和排序。然而,这种方法引入了大量的操作开销;我们必须维护一个流处理引擎、一个数据库和一个缓存。开云体育电动老虎机

Processing-On-Read

与前面的方法类似,其思想是在每个Cassandra节点上处理提交日志,并将事件发送到Kafka,而不需要重复数据删除和排序。与前面的方法不同,流处理部分被完全消除了。相反,原始事件将通过KCBQ直接上传到BigQuery。的观点在原始表之上创建,以处理重复数据删除、排序和合并列以形成完整的行。因为BigQuery视图是虚拟表,所以每次查询视图时,处理都是惰性的。为了防止视图查询变得过于昂贵,视图将定期物化。这种方法通过利用BigQuery来消除操作复杂性和代码复杂性大规模并行查询引擎.但是,缺点是非kcbq下游消费者必须自己完成所有工作。

考虑到流式Cassandra的主要目的是数据仓库,我们最终决定实现它processing-on-read.它为我们现有的用例提供了基本的特性,并提供了在将来扩展到上面提到的另外两个更通用的解决方案的灵活性。

开源

在为Cassandra构建实时数据管道的过程中,我们收到了对这个项目的大量兴趣。因此,我们决定开源Cassandra CDC代理开云体育官方注册网址雨伞是孵化连接器.如果您想了解更多信息或做出贡献,请查看正在进行中的pull请求源代码而且文档

在本系列博客文章的第二部分中,我们将更详细地阐述CDC实现本身。请继续关注!

乐高

Joy Gao是WePay的软件工程师,她专注于变化数据捕获、数据仓库和分布式系统。


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

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

参与

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

Baidu
map