12

当我们谈论采购事件时,我们有一个简单的双写架构,我们可以在其中写入数据库,然后将事件写入像 Kafka 这样的队列。其他下游系统可以读取这些事件并相应地处理/使用它们。

但是当尝试使数据库和事件同步时会出现问题,因为需要这些事件的顺序才能理解它。

为了解决这个问题,人们鼓励使用数据库提交日志作为事件源,并且围绕它构建了一些工具,如 Airbnb 的 Spinal Tap、Redhat 的 Debezium、Oracle 的 Golden Gate 等……它解决了一致性、排序保证和所有这些。

但是使用数据库提交日志作为事件源的问题是我们与数据库模式紧密耦合。微服务的数据库架构被暴露,数据库架构中的任何重大更改(如数据类型更改或列名更改)实际上都会破坏下游系统。

那么使用 DB CDC 作为事件源是个好主意吗?

讨论这个问题并使用 Debezium 进行事件溯源

4

3 回答 3

3

扩展康斯坦丁的答案:

TLDR;

交易日志拖尾/挖掘应该对其他人隐藏。

它不是严格意义上的事件流,因为您不应该直接从其他服务访问它。它通常在将遗留系统逐渐过渡到基于微服务时使用。流程可能如下所示:

  1. 服务 A 向数据库提交事务
  2. 框架或服务轮询提交日志并将新提交作为事件映射到 Kafka
  3. 服务 B 订阅了 Kafka 流并从那里消费事件,而不是从数据库

更长的故事:

服务 B 没有看到您的事件来自数据库,也没有直接访问数据库。提交数据应该被投射到一个事件中。如果您更改数据库,您应该只修改您的投影规则以将新模式中的提交映射到“旧”事件格式,因此不得更改消费者。(我不熟悉 Debezium,或者它是否可以做这个投影)。

您的事件应该是幂等的,因为在分布式场景中以原子方式发布事件和提交事务是一个问题,并且工具将保证至少一次交付并具有最佳的一次性处理语义,而一次性部分是更罕见。这是由于事件来源(事务日志)与其他服务将访问的流不同,即它是分布式的。这仍然是生产者部分,Kafka->consumer 频道也存在同样的问题,但原因不同。此外,Kafka 的行为不像事件存储,因此您实现的是消息队列。

如果可能,我建议使用专用的事件存储,例如 Greg Young 的:https ://eventstore.org/ 。这通过将事件存储和消息代理集成到单个解决方案中来解决问题。通过将事件(以 JSON 格式)存储到流中,您还可以“发布”它,因为消费者订阅了该流。如果您想进一步解耦服务,您可以编写将事件从一个流映射到另一个流的投影。您的事件消耗也应该是幂等的,但是您会得到一个由聚合分区并且读取速度非常快的事件存储。

如果您也想将数据存储在 SQL DB 中,则监听这些事件并根据它们插入/更新表,只是不要使用您的 SQL DB 作为事件存储,因为它很难正确实现(失败-证明)。

对于排序部分:将从一个流中读取事件进行排序。聚合多个事件流的投影只能保证源自同一流的事件之间的排序。它通常绰绰有余。(顺便说一句,如果需要,您可以根据消费者端的某些字段对消息重新排序。)

于 2019-01-26T22:47:54.307 回答
3

如果您使用事件溯源:

那么耦合不应该存在。事件存储是通用的,它不关心Aggregates的内部状态。您在最坏的情况下与事件存储本身的内部结构相结合,但这并不特定于特定的微服务。

如果您不使用事件溯源:

在这种情况下,聚合的内部结构和 CDC 组件(捕获数据更改并将事件发布到消息队列或类似的)之间存在耦合。为了限制这种耦合对微服务本身的影响,CDC 组件应该是其中的一部分。这样当微服务中聚合的内部结构发生变化时,CDC组件也会发生变化,而外界不会注意到。两个更改同时部署。

于 2019-01-26T17:18:16.493 回答
1

那么使用 DB CDC 作为事件源是个好主意吗?

“这是不是一个好主意?” 这个问题将取决于您的背景、您需要做出的不同权衡的成本和收益。

也就是说,这与我了解到的事件溯源的传统并不相符。

事件溯源——我们的记录簿是状态变化的分类账的想法——已经存在了很长时间。毕竟,当我们谈论“账本”时,我们实际上是在暗指几个世纪前写的那些记录商业的文件。

但是很多关于软件中事件溯源的讨论都深受领域驱动设计的影响。DDD 倡导者(除其他外)将您的代码概念与您正在建模的领域中的概念保持一致。

所以这就是问题所在:除非您处于极端情况下,否则您的数据库可能是您正在定制/配置以满足您的需求的一些通用应用程序。变更数据捕获将受到使用通用机制实现的事实的限制。所以产生的事件看起来像通用补丁文件(这里是之前和之后的区别)。

但是,如果我们试图将我们的事件与我们的领域概念对齐(即,这对我们的持久状态意味着什么),那么补丁文档是朝着错误方向迈出的一步。

例如,外域可能有多个“事件”,它们对我们模型中相同或非常相似的字段集进行更改。试图通过逆向工程来重新发现改变的动机是一个愚蠢的问题。尤其是当我们已经在学习用户界面设计时遇到过同样的问题。

在某些领域,通用的更改就足够了。在某些情况下,一个通用的改变现在就足够了。课程用马。

但这并不是“事件溯源”社区正在谈论的那种实现。

于 2020-04-04T04:27:42.310 回答