就我目前的一点点了解,“微服务”的核心概念之一就是它依赖于自己的数据库,独立于其他微服务。
深入探讨如何在微服务系统中处理分布式事务,最好的策略似乎是事件溯源模式,其核心是事件存储。
事件存储是否在不同的微服务之间共享?或者每个微服务都有多个独立的事件存储数据库和一个公共事件代理?
如果第一个选项是解决方案,使用 CQRS 我现在可以假设每个微服务的数据库都用作查询端,而共享事件存储在命令端。这是一个错误的假设吗?
既然我们在这个主题中:如果使用乐观锁定在 Stream 中进行并发写入,我必须重试多少次?
非常感谢您给我的每一条建议!
distributed-computing distributed-system event-sourcing microservices
我正在 AWS 上设计一个 Event Store,我选择了 DynamoDB,因为它似乎是最好的选择。我的设计似乎相当不错,但我面临一些我无法解决的问题。
**该设计
事件由对唯一标识(StreamId, EventId)
:
StreamId
:它与aggregateId 相同,这意味着一个聚合对应一个事件流。EventId
: 一个增量数字,有助于在同一事件流中保持排序事件保留在 DynamoDb 上。每个事件都映射到表中的单个记录,其中必填字段是 StreamId、EventId、EventName、Payload(可以轻松添加更多字段)。
partitionKey 是StreamId,sortKey 是EventId。
将事件写入事件流时使用乐观锁定。为了实现这一点,我使用了 DynamoDb 条件写入。如果已经存在具有相同(StreamId,EventId)的事件,我需要重新计算聚合,重新检查业务条件,如果业务条件通过,最后再次写入。
事件流
每个事件流由 partitionKey 标识。查询所有事件的流等于查询 partitionKey=${streamId} 和 0 到 MAX_INT 之间的 sortKey。
每个事件流标识一个且仅一个聚合。如前所述,这有助于使用乐观锁定处理同一聚合上的并发写入。这也可以在重新计算聚合时提供出色的性能。
活动发布
利用 DynamoDB Streams + Lambda 的组合发布事件。
重播事件
这就是问题开始的地方。让每个事件流只映射一个聚合(这会导致有大量的事件流),没有简单的方法可以知道我需要从哪些事件流中查询所有事件。
我正在考虑在 DynamoDB 中的某处使用额外的记录,该记录将所有 StreamId 存储在一个数组中。然后我可以查询它并开始查询事件,但是如果在我重播时创建了一个新流,我就会丢失它。
我错过了什么吗?或者,我的设计是错误的吗?
distributed-computing amazon-web-services event-sourcing amazon-dynamodb amazon-dynamodb-data-modeling
假设我们有 3 个不同的服务生成事件,每个服务都发布到自己的事件存储。
这些服务中的每一个都会消耗其他生产者服务事件。这是因为每个服务都必须处理另一个服务的事件并创建自己的投影。每个服务都在多个实例上运行。
(对我来说)最直接的方法是在每个 ES 前面放置“一些东西”,它正在挑选事件并将它们发布(发布/订阅)到每个其他服务的队列中。
这是完美的,因为每个服务都可以订阅它喜欢的每个主题,而事件发布者正在执行这项工作,并且如果服务不可用,事件仍然会传递。在我看来,这保证了高可扩展性和可用性。
我的问题是队列。我无法获得一个可轻松扩展的队列来保证消息的排序。它实际上保证了至少一次交付的“轻微失序”:需要明确的是,它是 AWS SQS。
因此,排序问题是:
我想我可以通过跟踪来自同一 ES 的事件的“序列号”来解决前两个问题。这可以通过跟踪我们消费事件的每个主题的最后一个序列号来完成。这应该很容易对事件做出反应并构建我们的投影。然后,当我从队列中弹出一个事件时,如果eventSequenceNumber > previousAppliedEventSequenceNumber + 1
我将其重新排队(或使其在一段时间内不可见)。
但事实证明,使用这个解决方案,当事件以高速率产生时,它会破坏性能(我可以使用可见性超时或其他东西,结果应该是相同的)。
这是因为当我期待事件 10 并暂时忽略事件 11 时,我还应该忽略序列号在事件 11 之后的所有事件(来自 ES),直到事件 11 再次出现并得到有效处理。
其他困难是:
lastSequenceNumber
.我缺少什么?
PS:对于第三个问题,请考虑以下场景。我们有 aUserService
和 a CartService
。它CartService
有一个投影,每个用户都可以跟踪购物车中的产品。UserCreated
每个购物车的投影还必须包含来自.NET 发布的事件的用户名和其他信息UserService
。如果UserCreated
出现在ProductAddedToCart
正常流程之后,则需要抛出异常,因为用户尚不存在。
我在微服务和事件来源方面还是个新手,我试图找出一种在AWS上部署整个系统的方法。
据我所知,有两种方法可以实现事件驱动的体系结构:
因此,我的基本策略是将每个命令转换为存储在DynamoDB中的事件,并利用DynamoDB流将新事件通知其他微服务。但是如何?我应该使用前两个解决方案中的哪一个?
第一个优点是:
但是缺点非常成问题:
第二个优点是:
缺点:
非常感谢您的各种建议!
event-driven amazon-web-services event-sourcing microservices