微服务 - 事件存储技术(在事件溯源解决方案中)是否在所有微服务之间共享?

9
据我目前的经验,关于“微服务”的核心概念之一是它依赖于独立于其他微服务的自己的数据库。
在深入了解如何处理微服务系统中的分布式事务时,最好的策略似乎是事件溯源模式,其核心是事件存储器。
事件存储器是否在不同的微服务之间共享?还是每个微服务有多个独立的事件存储器数据库和一个共同的事件代理?
如果第一种选择是解决方案,使用CQRS,我现在可以假设每个微服务的数据库都是查询端,而共享的事件存储器位于命令端。这是错误的假设吗?
既然我们正在讨论这个话题:在使用乐观锁定的情况下,在Stream中进行并发写入时,我需要重试多少次?
非常感谢您提前给我的任何建议!
3个回答

8
事件存储库是否在不同的微服务之间共享?或者每个微服务都有多个独立的事件存储数据库和一个共同的事件代理?
从它们的角度来看,每个微服务都应该写入自己的事件存储库。这可能意味着单独的实例或相同实例内的单独分区。这使得微服务可以独立扩展。
如果第一种选择是解决方案,则使用CQRS,我现在可以假设每个微服务的数据库都是查询方,而共享事件存储库位于命令方。这是错误的假设。
如上所述,每个微服务都应该有自己的事件存储库(或共享实例内的分区)。微服务不应向其他微服务的事件存储库追加事件。
关于读取事件,我认为通常应允许读取事件。轮询事件存储库是将更改传播到其他微服务的最简单(也是最好的)解决方案。它的优点是远程微服务以其能力和所需的事件轮询速率轮询。通过创建事件存储库副本,可以很好地扩展此功能,只要需要即可。
在某些情况下,您可能不希望从事件存储库中发布每个域事件。有人说可能存在内部域事件,其他微服务不应该依赖于它们。在这种情况下,您可以将事件标记为自由(或不自由)以供外部使用。
在微服务中传播更改的最清晰解决方案是具有其他微服务可以订阅的实时查询。它的优点是投影逻辑不会泄漏到其他微服务,但它也有劣势,即发射微服务必须定义+实现这些查询;您可以在注意到其他微服务重复投影逻辑时执行此操作。一个例子是电子商务应用程序中的总订单价格查询。您可以拥有类似于此的查询WhatIsTheTotalPriceOfTheOrder,每当添加/删除/更新订单中的项目时都会发布。
既然我们正在讨论这个话题:在使用乐观锁定的情况下,在流中进行并发写入时我需要重试多少次?
尽可能多,即直到写入成功。您可以设置99999的限制,只是为了检测重试机制出现严重问题时的情况。无论如何,并发写入仅应在同时进行写入在同一流上(对于一个聚合实例),而不是针对整个事件存储库时重试。

谢谢!你真的消除了我脑海中很多模糊的想法。 - Christian Paesante
还有一点:正如@VoiceOfUnreason所解释的,各种微服务不能依赖于事件存储在相同的事件存储技术上这个事实。这意味着理想的架构必须具有一个持久的代理,在其中发布消息并且该消息从另一个“代理”中获取并保存在事件存储中。这是实现原子发布和存储的唯一方式,但如果在处理事件时,当一个事件被拾取并存储时,同时也选择并存储了另一条信息,则可能会产生不一致的状态。有什么想法? - Christian Paesante
@ChristianPaesante 这是一个通用规则,微服务不应该假设彼此的技术,然而,“消息驱动”并不是一种技术。对于微服务A来说,微服务B如何生成事件并不重要,但重要的是它已经生成了事件。 - Constantin Galbenu
我的目标是获得一个良好的微服务“持久层”抽象。但我发现的挑战是,在监听代理事件以将其持久化到事件存储之前,是否要在消息代理上发布它们,或者直接将事件写入ES并利用ES提供的一些通知功能来获取更改通知。在第一种选择中,我无法获得一致性,而在第二种选择中,我无法保证不同的ES技术和微服务彼此不知道... - Christian Paesante
@ChristianPaesante 绝对要先写入事件存储。您可以使用接口进行抽象化。 - Constantin Galbenu

4
作为一种常规做法:在服务架构中,包括微服务,每个服务都在私有数据库中跟踪其状态。
"私有"这里主要意味着没有其他服务被允许对其进行写入或读取。这可能意味着每个服务都有自己的专用数据库服务器,或者服务可以共享单个设备,但只能访问自己的部分。
换句话说:服务之间通过公共 API 共享信息来相互通信,而不是向彼此的数据库写入消息。
对于使用事件溯源的服务,每个服务只能读取和写入其流。如果这些流恰好存储在同一个位置上-很好;但是,系统的正确性不应取决于不同服务将其事件存储在同一设备上。

2
TLDR:所有这些模式都适用于单个有界上下文(如果您喜欢,就是服务),不要在有界上下文之外分发领域事件,将集成事件发布到ESB(企业服务总线)或类似的东西作为公共接口。
好的,所以我们有三个模式要简要介绍,然后再一起讨论。
  1. 微服务
  2. CQRS
  3. 事件溯源
微服务 核心目标:将系统中的更改隔离和解耦为单个服务,使其能够独立部署和测试,而不会产生副作用。这通过封装公共API并限制服务之间的运行时依赖关系来实现。 CQRS 核心目标:在单个服务中隔离和解耦写入关注点和读取关注点。这可以通过几种方式实现,但核心思想是读取模型是为查询优化的写模型的投影。
事件溯源
核心目标:使用业务领域规则作为数据模型。这是通过将状态建模为不可变的域事件的追加流,并通过从开始重放流来重新构建当前聚合状态来实现的。
全部在一起。
这里有很多精彩的内容https://learn.microsoft.com/en-us/previous-versions/msp-n-p/jj554200(v=pandp.10)。每个内容都有其自身的复杂性、权衡和挑战,虽然是一项有趣的练习,但您应该考虑成本是否超过了收益。所有这些都适用于单个服务或边界上下文。一旦您开始在服务之间共享数据存储,就会面临问题,因为共享的数据存储不能在隔离的情况下更改,因为它现在是公共接口。
最好尝试将integration events发布到共享总线上,作为其他服务和边界上下文消费和使用来构建其他域上下文数据投影的公共接口。
发布集成事件作为当前聚合状态的幂等快照(upsert X,delete X)是一个好主意,特别是如果您的总线不是持久的。这使您可以在需要时从域中重新发布集成事件,而不会在消费者之间产生不一致的状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接