【问题标题】:Microservices - Is event store technology (in event sourcing solutions) shared between all microservices?微服务 - 事件存储技术(在事件源解决方案中)是否在所有微服务之间共享?
【发布时间】:2019-03-03 19:21:54
【问题描述】:

据我目前的一点经验让我理解,“微服务”的核心概念之一是它依赖于自己的数据库,该数据库独立于其他微服务。

深入研究如何在微服务系统中处理分布式事务,最好的策略似乎是事件溯源模式,其核心是事件存储。

事件存储是否在不同的微服务之间共享?或者每个微服务有多个独立的事件存储数据库和一个公共事件代理?

如果第一个选项是解决方案,那么使用 CQRS 我现在可以假设每个微服务的数据库都用作查询端,而共享事件存储位于命令端。这是一个错误的假设吗?

既然我们在主题中:如果使用乐观锁定在 Stream 中并发写入,我必须重试多少次?

非常感谢您给我的每一条建议!

【问题讨论】:

    标签: microservices distributed-computing event-sourcing distributed-system


    【解决方案1】:

    事件存储是否在不同的微服务之间共享?或者每个微服务有多个独立的事件存储数据库和一个公共事件代理?

    从他们的角度来看,每个微服务都应该写入自己的事件存储。这可能意味着同一实例内的单独实例或单独分区。这允许微服务独立扩展。

    如果第一个选项是解决方案,那么使用 CQRS 我现在可以假设每个微服务的数据库都用作查询端,而共享事件存储位于命令端。这是一个错误的假设吗?

    有点。正如我在上面所写的,每个微服务都应该有自己的事件存储(或共享实例内的分区)。微服务不应将事件附加到其他微服务事件存储中。

    关于阅读活动,我认为阅读活动一般应该是被允许的。轮询事件存储是将更改传播到其他微服务的最简单(也是我认为最好的)解决方案。它的优点是远程微服务以它可以的速率和它想要的事件进行轮询。这可以通过创建事件存储副本来很好地扩展,只要需要。

    在某些情况下,您不想发布事件存储中的每个域事件。有人说可能存在其他微服务不应该依赖的内部域事件。在这种情况下,您可以将事件标记为免费(或不免费)以供外部使用。

    在微服务中传播更改的最简洁的解决方案是拥有其他微服务可以订阅的实时查询。它的优点是投影逻辑不会泄漏到其他微服务,但也有缺点是发射微服务必须定义+实现这些查询;当您注意到其他微服务重复投影逻辑时,您可以这样做。此查询的一个示例是电子商务应用程序中的总订单价格。您可以有一个像 WhatIsTheTotalPriceOfTheOrder 这样的查询,每次在订单中添加/删除/更新项目时都会发布该查询。

    既然我们在主题中:如果使用乐观锁定在 Stream 中并发写入,我必须重试多少次?

    根据需要,即直到写入成功。您可以有 99999 的限制,只是为了检测重试机制何时出现严重错误。在任何情况下,只有在同一时间在同一个流上(对于一个 Aggregate 实例)而不是整个 Event 存储区同时完成写入时,才应重试并发写入。

    【讨论】:

    • 谢谢!你真的清除了我脑海中很多模糊的想法。
    • 另一件事:正如@VoiceOfUnreason 解释的那样,各种微服务不能依赖于事件存储在同一个事件存储技术上的事实。这意味着如果您发布消息并且该消息是从另一个“代理”中挑选并保存在事件存储中,那么理想的架构必须具有持久代理。这是实现原子发布和存储的唯一方法,但是如果事件被拾取并存储,而在中间也被拾取并存储了另一条消息,这可能会产生不一致的状态。想法?
    • @ChristianPaesante 这是一般规则,微服务不应该假设任何关于彼此的技术,但是,“消息驱动”不是一种技术。 ms B 如何生成事件与 ms A 无关,但与生成事件相关。
    • 我的目标是对我的微服务的“持久层”进行良好的抽象。但我发现的挑战是,是在侦听代理事件之前在消息代理上发布以将它们保存在事件存储中,还是直接在 ES 上编写事件并利用 ES 提供的一些通知功能来获得通知变化。在第一个选项中我无法获得一致性,而在第二个选项中我不能保证不同的 ES 技术和 ms 不知道彼此......
    • @ChristianPaesante 肯定会先写信给事件存储。您可以使用接口对其进行抽象。
    【解决方案2】:

    通常:在包含微服务的服务架构中,每个服务在私有数据库中跟踪其状态。

    这里的“私有”主要是指不允许其他服务对其进行写入或读取。这可能意味着每个服务都有自己的专用数据库服务器,或者服务可能共享一个设备但只有自己的部分的访问权限。

    另一种表达方式:服务之间通过公共 api 共享信息进行通信,不是通过将消息写入彼此的数据库。

    对于使用事件溯源的服务,每个服务只能对其流进行读写访问。如果这些流恰好存储在同一个家中 - 很好;但系统的正确性不应依赖于将其事件存储在同一设备上的不同服务。

    【讨论】:

      【解决方案3】:

      TLDR:所有这些模式都适用于单个有界上下文(如果您愿意,可以提供服务),不要在有界上下文之外分发域事件,将集成事件发布到 ESB(企业服务总线)或类似的东西上,因为公共接口。

      好的,我们这里有三个模式,分别简要介绍,然后一起介绍。

      1. 微服务
      2. CQRS
      3. 事件溯源

      微服务

      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)的幂等快照,尤其是在您的总线不是持久性的情况下。这允许您在需要时从域重新发布集成事件,而不会在消费者之间产生不一致的状态。

      【讨论】:

        猜你喜欢
        • 2017-05-27
        • 2020-02-23
        • 2020-09-12
        • 2020-01-26
        • 1970-01-01
        • 2016-07-30
        • 2016-11-05
        • 1970-01-01
        • 2019-11-02
        相关资源
        最近更新 更多