【发布时间】:2021-11-20 10:04:17
【问题描述】:
作为一名经验丰富的开发人员,我只是进入微服务和事件驱动架构的世界。与传统的单体方法相比,我认为松散耦合、独立可扩展性和异步业务流程的正确实现之类的事情应该得到简化。所以尝试一下,为自己制作一个简单的 PoC。 我正在考虑制作一个简单的应用程序,用户可以在其中注册、登录和更改客户详细信息。但是,我想对某些事件异步做出反应:
- 客户登录 - 如果使用的 IP 地址对系统来说是新的,我们会向他们发送电子邮件。
- 客户更改姓名,我们会向他们发送电子邮件通知更改。
我们的想法是制作一个对“CustomerLoggedIn”、“CustomerChangeName”事件做出反应的单独应用程序。 在这里,我可以想到三种方法,如何实现这个简单的功能,每种方法都有一些缺点。因此,当客户提交姓名更改时:
-
存储更改名称 更改的名称存储在数据库中 + 当数据库事务完成时,将向 Kafkas 发送一个事件。这里出现的一个大问题是,如果客户打开了 2 个选项卡,并且几乎同时在一个选项卡中提交了从初始名称“Bob”到“Alice”的更改,在另一个选项卡中从“Bob”到“Jim”,在数据库级别的更新之一覆盖另一个,这没关系,但是我们不能保证事件的顺序是相同的。我们可以使用一些检查来确保仅在看到“最后一个版本”时才进行数据库更新,从而完全防止第二次更新,因此只会发出一个事件。但在一般情况下,这种模式不允许我们在数据库中保留与 Kafka 中相同的事件顺序,除非我们在一个分布式事务中执行数据库更改 + Kafka 事件发送,这是反模式 afaik。
-
在 DB 中更改名称,并使用 Debezium 或类似的 DB CDC 来捕获事件并将其流式传输。在这里,我们得到一个单一的事件源,因此排序问题得到了解决,但是困扰我的是我失去了用业务信息丰富事件的能力。另一个相关的缺点是 CDC 将流式传输“客户”表中的所有更新,而不管事件的业务含义如何。因此,在这种情况下,我可能需要构建一个 Kafka Streams 应用程序来将 DB CDC 事件转换为业务事件,并将 DB 结构与事件结构分离。这种方法的潜在好处是我将能够以与源自应用程序相同的方式捕获“直接”数据库更改。
-
从应用程序发出事件,而不将其存储在数据库中。一个订阅者可能会使用 DB 持久性,另一个订阅者会发送电子邮件等。我在这里看到的最大问题是 - 我应该向客户端返回什么?我不能说“好吧,你的名字改了”,更像是“好吧,你的请求已经被记录了,将被处理”。如果客户快速点击刷新 - 他希望看到他的新名称,因为我们不想向客户解释什么是最终一致性,是吗?此外,“email sender”和“db updater”处理同一事件的顺序也不能保证,所以我可以在更改保留之前发送电子邮件。
我正在寻找关于这三种方法中的任何一种的建议(可能还有一些我缺少的方法),也许是一种比其他方法更受欢迎的用例?
【问题讨论】:
标签: apache-kafka microservices debezium event-driven event-driven-design