为什么需要CDC和领域事件通知?
之前单体应用都是基于请求响应式的服务,应用各模块之间交互的主要途径是基于共享的数据库,一般不会主动通知,主要是通过修改数据库来共享状态。
应用(微)服务化以后,各服务之间不再共享数据库,那么之前的交互方式变失效了。那怎么在模块间交互信息,主要是怎么主动发出变更通知。
1. 主动发出领域事件到消息中间件,其他模块订阅相关消息来获取通知
2. 采用CDC 变更数据捕获,然后发送到消息中间件,其他模块订阅相关消息来获取通知
时代变了,思路也得跟着变。
下边的文章主要介绍了CDC 的好处。
原文地址:
昨天我有机会向 Java 用户组 Darmstadt Java 用户组介绍 Debezium 和变更数据捕获 (CDC) 的想法。这是一个美好的夜晚,有很多有趣的讨论和问题。问题之一如下:使用基于日志的更改数据捕获工具(例如 Debezium)与简单地轮询更新记录相比有什么优势?
那么首先,这两种方法有什么区别?使用基于轮询(或基于查询)的 CDC,您可以重复运行查询(例如,通过 JDBC)以从要捕获的表中检索任何新插入或更新的行。相比之下,基于日志的 CDC 通过对数据库日志文件(例如 MySQL 的 binlog 或 MongoDB 的 op 日志)的任何更改做出反应来工作。
由于这不是第一次提出这个问题,我想我也可以在博客上提供更广泛的答案。这样我将来就可以参考这篇文章,如果问题再次出现:)
因此,事不宜迟,下面是我列出的基于日志的 CDC 相对于基于轮询的方法的五个优点。
1. 捕获所有数据更改
通过读取数据库的日志,您可以获得所有数据更改的完整列表,这些更改的确切应用顺序是。这对于您对记录更改的完整历史感兴趣的许多用例至关重要。相比之下,使用基于轮询的方法,您可能会错过在轮询循环的两次运行之间发生的中间数据更改。例如,可能会在两次轮询之间插入和删除记录,在这种情况下,基于轮询的 CDC 永远不会捕获该记录。
与此相关的是停机时间方面,例如在更新 CDC 工具时。使用基于轮询的 CDC,一旦 CDC 工具重新联机,将只捕获给定记录的最新状态,而忽略在停机期间发生的对记录的任何早期更改。基于日志的 CDC 工具将能够从关闭之前停止的点恢复读取数据库日志,从而捕获数据更改的完整历史记录。
2. 事件延迟低,同时避免增加 CPU 负载
通过轮询,您可能会想增加轮询尝试的频率,以减少丢失中间更新的机会。虽然这在一定程度上有效,但轮询过于频繁可能会导致性能问题(因为用于轮询的查询会导致源数据库负载)。另一方面,扩大轮询间隔将减少 CPU 负载,但不仅可能导致错过更改事件,还会导致传播数据更改的延迟更长。基于日志的 CDC 允许您近乎实时地对数据更改做出反应,而无需花费 CPU 时间反复运行轮询查询。
3.对数据模型没有影响
轮询需要一些指标来识别自上次轮询以来已更改的记录。所以所有捕获的表都需要有一些列LAST_UPDATE_TIMESTAMP
,可用于查找更改的行。在某些情况下,这可能没问题,但在其他情况下,这种要求可能并不理想。具体来说,您需要确保在写入应用程序或例如通过触发器捕获的所有表上正确维护更新时间戳。
4.可以捕获删除
自然地,轮询不允许您识别自上次轮询以来已删除的任何记录。通常,对于类似复制的用例来说,这是一个问题,您希望在源数据库和复制目标上拥有相同的数据集,这意味着您还希望删除接收器端的记录,如果它们已在源数据库。
5.可以捕获旧记录状态和更多元数据
根据源数据库的功能,基于日志的 CDC 可以为更新和删除事件提供旧记录状态。而通过轮询,您只会获得当前行状态。对于许多用例来说,在单个更改事件中方便地使用旧行状态可能会很有趣,例如,如果您想向应用程序用户显示带有旧列值和新列值的完整数据更改以进行审计。
此外,基于日志的方法通常可以提供模式更改流(例如以应用的 DDL 语句的形式)并公开额外的元数据,例如事务 ID 或应用特定更改的用户。这些事情通常也可以通过基于查询的方法来实现(取决于数据库的功能),不过我还没有真正看到它在实践中完成。
概括
就是这样,基于日志的变更数据捕获的五个优势。请注意,这并不是说基于轮询的 CDC 没有其应用程序。例如,如果您的用例可以通过每小时传播一次更改来满足,并且错过在其间有效的记录的中间版本不是问题,那么它可以完全没问题。
但是,如果您对近乎实时地捕获数据更改感兴趣,确保不会错过任何更改事件(包括删除),那么我非常建议您探索基于日志的 CDC 的可能性,因为它已启用德比西姆。Debezium 连接器为您完成所有繁重的工作,即您不必处理各个数据库的所有低级细节以及从其日志中获取更改的方法。相反,您可以使用 Debezium 生成的通用且在很大程度上统一的更改数据事件.
使用场景
1. 能有助于缓存失效
Redis和Memcached等键值存储用作缓存以加快读取速度。通常,他们将预先计算的 SQL 查询结果保存在内存中,以便可以消除对数据库的后续访问。
缓存最大的挑战是如何让缓存的数据与源数据保持一致。例如,源数据库中的记录更新多久传播到缓存?
通常,缓存会超时并定期自动失效。但是在 CDC 的帮助下,缓存的条目可以以事件驱动的方式失效。
假设我们有一个 DynamoDb 表来捕获对候选人的投票。每当记录新投票时,它都会作为事件捕获并发布到 DynamoDb 流,由 Lambda 函数处理。该函数的逻辑聚合投票计数并将其写入 ElasticCache。因此,仪表板可以直接读取缓存的结果,而无需 DynamoDb 每次都运行聚合。
2.更新一个搜索索引,比如Elasticsearch
我们经常使用 OLTP 数据库作为我们的操作记录系统。但它们不适合执行诸如全文搜索之类的专门操作。虽然数据库可以配备相关的扩展,但人们经常将全文搜索操作卸载到像 Elasticsearch 这样的专门系统。
例如,我们可以在 Elasticsearch 中维护一个高度非规范化的聚合视图,以满足客户订单等查询。在关系数据库中,此查询将通过连接多个表来提供,如果要连接的行数很多且查询频繁,则它是不可扩展的。但 Elasticsearch 可以将这些信息捕获到单个文档中,并使消费者能够按产品名称搜索订单。
我们在这里面临的挑战是如何将源系统更改可靠地传播到 Elasticsearch 并始终保持两个系统一致。
在这一点上,像 Debezium 这样的 CDC 系统可以通过检测源数据库更改并以可扩展且可靠的方式将它们传播到 Elasticsearch 来帮助您。
Debezium 获取 MySQL 的行级更改并将其写入 Kafka 主题。然后,部署到 Kafka Connect 的 Elasticsearch sink 连接器读取更改并传播到 Elasticsearch 的相关索引。您可以从这里阅读更多相关信息。
3.实时数据加载到数据仓库
操作数据库不是运行繁重分析工作负载的好选择,因为它们会阻碍常规 OLTP 操作的性能。因此,必须将运营数据移动到专用系统(例如数据仓库)以运行支持 BI 和报告需求的分析查询。
有两种方法;ETL 是传统的方法,您可以批量操作数据并定期将它们加载到仓库。ETL 的缺点是延迟。但是使用 CDC,您可以在源系统更改发生时捕获它们并将它们实时传送到仓库。
今天,许多数据仓库允许以流方式加载数据。AWS Redshift、Google BigQuery、Apache Druid 和 Apache Pinot 就是几个例子。
您可以捕获 DynamoDb 表的更改并将它们写入 Kinesis 流。然后使用 Kinesis Firehose 将它们加载到 RedShift。同样,您可以使用 Debezium 将操作数据移动到 Kafka 主题中,Apache Pinot 可以以流式方式读取该主题。
4. 将本地数据同步到云端
有时,通常需要将在诸如本地系统(例如 POS 系统、COTS 应用程序)等边缘位置产生的操作数据移动到位于云中的中央数据库。主要目标是利用云供应商提供的可扩展和持久的存储选项。
例如,本地事务数据可以发送到云数据仓库,在那里可以执行丰富的分析操作,而无需在本地配置昂贵的基础设施。另一个用例是将本地数据迁移到云中提供的新应用程序。
您可以利用 CDC 有效地捕获本地数据库更改并将其传播到云。大多数情况下,它是作为位于本地和云的两个数据库之间的连续数据复制来完成的。
5. 微服务物化视图的事件驱动更新
微服务架构提倡每个服务都有一个数据库来保存服务私有的数据。尽管这提高了跨服务的自治性和可扩展性,但这可能会导致一些复杂情况。
例如,当一个服务尝试访问另一个服务拥有的数据时,唯一的方法是进行 API 调用。但是当涉及级联 API 调用时,此模型不可扩展。消费者必须执行低效的内存中连接才能保持来自多个服务的响应。
作为一种补救措施,微服务依靠命令查询职责分离(CQRS)模式将状态突变与查询分离。服务可以侦听来自下游系统的域事件并更新内部物化视图以在本地执行查询,而不是实时查询服务。这提高了读取性能、整体系统可用性和自主性。
6. 使用发件箱模式进行可靠的微服务数据交换
微服务的另一个常见问题是跨多个服务边界可靠地更新数据。例如,考虑一个管理采购订单的微服务。下新订单时,可能必须将有关该订单的信息转发给运输服务和客户服务。
Saga模式在一定程度上有助于解决这个问题。但是由于其同步性质,实现 Saga 通常很复杂和脆弱。
CDC 通过捕获对发件箱表所做的更改并以可靠且最终一致的方式将它们传播到下游微服务来进入画面。
Debezium 博客有一篇关于使用 Debezium 实现这一点的优秀文章。
7.实时信息发布
CDC 允许您将源数据库中的更改作为事件流捕获。然后可以使用Apache Flink等流处理引擎处理这些事件,以实时应用转换或运行聚合。清理后的事件比它们的原始版本更有意义。因此它们可以用于人类消费,如下所示。
更新实时仪表板
Microsoft Power BI 等仪表板可以通过从流数据集中读取来实时更新。
发布到异步 API
处理后的更改事件可以写入 WebSocket,以便订阅者可以采取适当的操作。
8. 建立审计日志
维护审计日志是业务应用程序的常见要求,即应用程序数据的所有更改的持久跟踪。
在其自然形式中,像 Debezium 这样的 CDC 系统根据更改应用于源系统的顺序来捕获、存储和传播更改。因此,接收此数据的目标系统可以建立已应用于源系统的更改的时间顺序并追溯到特定时间点。
可以使用来自外部系统的信息来丰富变化,以提供有助于对事件进行取证分析的整体视图。例如,通过从头开始重放审计日志,可以找到谁在哪个时间做了什么操作的答案。