microservices - 使用数据库 CDC 的事件溯源是否被认为是好的架构?

标签 microservices cqrs software-design event-sourcing debezium

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

但是当尝试使数据库和事件同步时会出现问题,因为需要对这些事件进行排序才能使其有意义。

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

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

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

A talk on this problem and using Debezium for event sourcing

最佳答案

扩展康斯坦丁的回答:

TLDR;

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

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

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

  • 更长的故事:

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

    您的事件在发布事件和提交事务时应该是幂等的
    原子地是分布式场景中的一个问题,工具将保证至少一次交付,最多只能使用一次处理语义,而恰好一次的部分很少见。这是由于事件源(事务日志)与其他服务将访问的流不同,即它是分布式的。这仍然是生产者部分,Kafka->消费者 channel 存在同样的问题,但原因不同。另外,Kafka will not behave like an event store ,所以你实现的是一个消息队列。

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

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

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

    关于microservices - 使用数据库 CDC 的事件溯源是否被认为是好的架构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54379623/

    相关文章:

    c# - 使用另一个服务中的托管身份对服务调用者进行身份验证

    微服务设计中的 ElasticSearch

    java - 命令队列引导代码看起来像服务定位器模式而不是依赖注入(inject)

    c - 在单独的头文件中定义的类型的 typedef

    Kubernetes - 服务网格是必须的吗?

    spring-mvc - 如何使用 Feign 客户端设置请求头?

    domain-driven-design - DDD/CQRS/ES 使用图形数据库实现聚合成员,也就是使用立即一致的 readModel 作为实体集合

    c# - CQRS 和 WebAPI 设计

    c++ - 如何设计窗口渲染循环?

    c++ - 结构中的默认成员值或默认构造函数参数?