据我最近的经验所知,关于“微服务”的核心概念之一是它依赖于自己的数据库,该数据库独立于其他微服务。
深入研究如何在微服务系统中处理分布式事务,最好的策略似乎是事件采购模式,其核心是事件存储。
事件存储是否在不同的微服务之间共享?还是每个微服务都有多个独立的事件存储数据库和一个公共事件代理?
如果第一个选择是解决方案,那么现在我可以使用CQRS假设每个微服务的数据库都应作为查询方,而共享事件存储则应在命令方。这是一个错误的假设吗?
而且由于我们处于主题中:如果使用乐观锁定在Stream中并发写入,我必须执行多少次重试?
非常感谢您可以给我的每条建议!
答案 0 :(得分:2)
通常:在包含微服务的服务体系结构中,每个服务在私有数据库中跟踪其状态。
此处的“私人”主要是指不允许有其他服务写入或读取该服务。这可能意味着每个服务都拥有自己的专用数据库服务器,或者服务可能共享一个设备,但仅对其自己的组件具有访问权限。
以另一种方式表示:服务通过公共api共享信息来彼此通信,而不是通过将消息写入彼此的数据库来实现通信。
对于使用事件源的服务,每个服务只能对其流进行读写访问。如果这些流恰好存储在同一个家庭中-很好;但是系统的正确性不应该取决于将事件存储在同一设备上的不同服务。
答案 1 :(得分:1)
事件存储是否在不同的微服务之间共享?还是每个微服务都有多个独立的事件存储数据库和一个公共事件代理?
从它们的角度来看,每个微服务都应写入其自己的事件存储。这可能意味着单独的实例或同一实例内的单独分区。这使得微服务可以独立扩展。
如果第一个选择是解决方案,那么现在我可以使用CQRS假设每个微服务的数据库都应作为查询方,而共享事件存储则应在命令方。这是一个错误的假设吗?
金田。正如我在上面所写,每个微服务都应具有自己的事件存储(或共享实例中的分区)。微服务不应将事件追加到其他微服务事件存储中。
关于阅读事件,我认为阅读事件通常应该被允许。轮询事件存储是将更改传播到其他微服务的最简单(也是我认为最好的)解决方案。它的优点是远程微服务以其可以的速率和所需的事件进行轮询。通过创建事件存储副本,可以根据需要进行任意缩放。
在某些情况下,您不想从事件存储中发布每个域事件。有人说可能存在其他微服务不应该依赖的内部域事件。在这种情况下,您可以将事件标记为免费(或不免费)以供外部消费。
在微服务中传播更改的最干净的解决方案是对其他微服务可以订阅的实时查询。这样做的优点是,投影逻辑不会泄漏到其他微服务,但也有缺点,发出微服务必须定义并实现那些查询。当您发现其他微服务重复了投影逻辑时,可以执行此操作。此查询的一个示例是电子商务应用程序中的总订单价格。您可能会遇到这样的查询WhatIsTheTotalPriceOfTheOrder
,每次在订单中添加/删除/更新商品时都会发布该查询。
而且由于我们处于主题中:如果使用乐观锁定在Stream中并发写入,我必须执行多少次重试?
根据需要,即直到写入成功为止。您可以将其限制为99999,以便在重试机制出现严重错误时进行检测。无论如何,仅当在同一流上对同一流(对于一个Aggregate实例)同时进行一次写入时,而不是对整个事件存储区进行
,才应重试并发写入。答案 2 :(得分:1)
TLDR:所有这些模式都适用于单个有界上下文(服务,如果您愿意),不要在有界上下文之外分发域事件,将集成事件发布到 ESB(企业服务总线)或类似的东西上,作为公共接口。
好的,我们这里有三种模式,分别简要介绍,然后一起介绍。
微服务
https://docs.microsoft.com/en-us/azure/architecture/microservices/ 核心目标:将系统中的更改与单个服务隔离开来,实现独立部署和测试,而不会产生附带影响。 这是通过将更改封装在公共 API 后面并限制服务之间的运行时依赖性来实现的。
CQRS
https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs 核心目标:在单个服务中将写入关注点与读取关注点隔离并解耦。 这可以通过几种方式实现,但核心思想是读取模型是为查询优化的写入模型的投影。
事件溯源
https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing 核心目标:使用业务领域规则作为您的数据模型。 这是通过将状态建模为不可变域事件的仅附加流并通过从头开始重放流来重建当前聚合状态来实现的。
一起
这里有很多很棒的内容https://docs.microsoft.com/en-us/previous-versions/msp-n-p/jj554200(v=pandp.10) 每一个都有自己的复杂性、权衡和挑战,虽然这是一项有趣的练习,但您应该考虑成本是否大于收益。所有这些都适用于单个服务或有界上下文。一旦您开始在服务之间共享数据存储,您就会面临各种问题,因为共享数据存储现在是一个公共接口,因此无法单独更改。
而是尝试将 integration events 发布到共享总线作为其他服务和有界上下文的公共接口,以使用和用于构建其他域上下文数据的投影。
将集成事件发布为当前聚合状态(更新插入 X、删除 X)的幂等快照是一个好主意,尤其是当您的总线不是持久的时。这允许您在需要时从域重新发布集成事件,而不会在使用者之间产生不一致的状态。