何时及为何应使用CDC

207 阅读8分钟

变更数据捕获(CDC)可以简化和改善你的应用程序和数据架构。诀窍在于找出最有效的用例,在这些用例中,采用 CDC 会产生预期的影响。在这篇博客中,我将解读两个有用的 CDC 用例。第一个是流式数据到你的数据仓库,第二个是事件驱动的架构。这绝不是变化数据捕获的唯一两个用例,但它们是展示 CDC 能够简化应用程序和数据架构的绝佳例子。

什么是变更数据捕获(CDC)?

变更数据捕获是一组技术,它允许你识别和捕获数据库中已发生变化的数据,以便你能在稍后阶段利用这些数据采取行动。

使用CDC将数据流传输到你的数据仓库

将数据从你的数据库流向你的数据仓库要经过一个叫做ETL或ELT的过程。CDC可以使这个过程更有效率。

什么是ETL和ELT?

  • ETL是指 "提取-转换-加载",即从主数据库中提取数据,对其进行一些数据转换(聚合或连接),然后将这些数据放入数据仓库,用于分析查询。
  • ELT是现在一个更常见的概念,在这里,你不是在加载前进行转换,而是将原始数据加载到你的数据仓库中,然后再进行聚合和连接。

批量数据与流数据

传统的ETL是基于数据的批量加载。你可以通过以下两种方式来实现:一是每晚做一次大的查询,从数据库中提取所有的数据,然后刷新你的数据仓库;二是以某种周期性的节奏轮询你的数据库,例如每半小时或一小时,来获取新的数据,并将新的数据加载到你的数据仓库中。无论哪种方式,这个过程都有三个很大的缺点。

  1. 负载的周期性高峰。这些大型查询会影响延迟,最终影响用户体验,这就是为什么很多公司倾向于把高峰期安排在低流量时期。
  2. 网络配置。发送所有这些数据给你的网络带来了很大的压力。因为你的网络成本和你在网络上发送的字节有很大的峰值,你必须配置你的网络,以便能够处理峰值流量和峰值批量发送数据。
  3. 延迟业务决策。基于数据的业务决策会因为你的轮询频率而延迟。因此,如果你每天晚上更新你的数据,这意味着你不能查询昨天发生的事情,直到第二天。

使用变化数据捕获将数据从主数据库流向数据仓库可以解决这三个问题,原因如下。

  1. CDC不要求你定期执行高负载的查询,所以你不会在负载方面出现真正的尖峰行为。虽然变化馈送不是免费的,但它们更便宜,而且它们在一天内均匀分布。
  2. 因为数据是连续发送的,而且是小得多的批次,所以你不需要提供那么多的网络来使其发挥作用,你可以节省网络成本。
  3. 因为你不断地将数据从你的数据库流向你的数据仓库,你的仓库中的数据是最新的,允许你创建实时的洞察力,使你比你的竞争对手更有优势,因为你是在更新鲜的数据上做出商业决策。

将CDC用于事件驱动架构

事件驱动的架构中,最难完成的事情之一是在服务边界之间安全、一致地交付数据。通常情况下,事件驱动架构中的单个服务需要向该服务的本地数据库以及消息传递队列提交更改,以便将需要发送给另一个服务的任何消息或数据片断都可以这样做。但这是一个挑战。如果你的消息提交到了你的数据库,但没有提交到消息队列中,会发生什么?如果消息被发送到服务中,但它实际上并没有在你的数据库中提交,会发生什么?

为了使这个问题更加具体,让我们想想一个假想的(目前不可能的)社交活动应用程序,叫做MeetWithMeTomorrow。用户可以进入该应用程序,创建一个事件,邀请他们的朋友,然后确认该事件。而当该事件被确认后,会向你的朋友发送一个推送通知,让他们知道在哪里与你见面。在这个模拟架构中,数据是这样移动的。

  1. 创建事件的用户将把事件发送到事件跟踪数据库以及kafka消息传递队列中。
  2. 然后将其传播到通知服务上。
  3. 然后,通知服务将向你邀请的每个人发送推送通知。

这种架构的问题是,有时kafka队列并没有收到你的消息。当这种情况发生时,推送通知不会被发送,但事件创建者认为他们已经发送了。这是一个令人困惑的用户体验。

相反,如果事件进入了kafka队列,推送通知被发送给了该用户的朋友,但它没有被提交到数据库中,用户就不知道这些推送通知被发送了。所以用户的朋友会出现,但用户不会。这又是一次糟糕的经历。

有一些变通方法可以解决这个问题。你可以添加应用逻辑,只有当它检测到消息被提交到事件跟踪数据库并成功发布到你的kafka队列时,才会认为事件被创建。在这种情况下,例如,你的应用程序可以成为你所写的kafka主题的订阅者,这样,它就可以知道消息正确传播了。这里的问题是,你会遇到这样的情况:你不断地试图写到你的事件跟踪数据库,而消息成功地进入了kafka队列。最终,该事件要么被创建,要么被回滚--但通知已经被发送给该用户的朋友,即使该用户看到这个事务是待定的。此外,这还增加了很多复杂的应用逻辑,你真的不需要实现这个目标。

一个更简洁的解决方案是将收件箱模式与变更数据捕获技术结合起来使用。发件箱模式的一般概念是,除了在每个事务中向事件跟踪数据库中的其他表写入外,你还向一个特殊的发件箱表写入。而不是同步地写入你的kafka队列,你要等待数据库事务的提交。你将变化数据捕获指向发件箱表,并将变化异步地排放到你的发件箱表和你的kafka队列中。

在MeeWithMeTomorrow的例子中,在同一个写事务中,你不是只写到你的事件和你的与会者表,而是也会写到你的发件箱表。当该事务提交时,变化数据捕获正在监听该表的变化,并将该新事件发射到你的kafka队列,然后发射到你的通知服务。

使用Outbox模式与变化数据捕获的三个好处:

  1. 生命是短暂的--避免复杂的应用逻辑。
  2. 通过使用一个发件箱,你有一个应该被发射的事件的历史。这让你可以审计你的应用程序正在做什么,而且,如果你的kafka服务器宕机了,或者你遇到了其他问题,你可以随时重放这些事件。所以你永远不会丢失任何应该被发送到你的通知服务的消息。
  3. 你可以定制存储在你的发件箱表中的数据,最终以最有利于消费者的格式发送到你的服务下游。这也意味着,如果你改变了你的事件或与会者表的模式,你不一定要改变放入发件箱表中的内容--这减少了系统接口的流失。

变更数据捕获的更多用例

在事件驱动的架构中使用变更数据捕获或将数据流转到数据仓库只是CDC可以简化和改善您的应用程序和数据架构的两个用例。还有很多其他的用例,CDC 在其中提供了类似的价值。我想到的几个例子是。

  • 流式更新您的搜索索引
  • 流式分析和异常情况检测
  • 流式更新您的在线数据存储,用于生产机器学习模型

希望我在这里提供的变化数据捕获例子是有帮助的。如果你有任何进一步的问题,请在CockroachDB社区Slack中联系。如果你想看一个现有的CockroachDB用户的事件驱动架构的例子,请看这个案例研究