21

在微服务架构的上下文中,同步(可能是REST基于)机制。

考虑到这种情况并想象一个过于简化的订购系统,如下图所示:

订购系统

以及以下消息流:

  • 订单来自某个来源(网络/移动设备等)
  • 订单服务接受订单并发布CreateOrderEvent
  • InventoryService 对 做出反应CreateOrderEvent,做一些库存工作并InventoryUpdatedEvent在完成后发布
  • Invoice 服务然后对 做出反应InventoryUpdatedEvent,发送发票并发布EmailInvoiceEvent

所有服务都已启动,我们愉快地处理订单……每个人都很高兴。然后,库存服务因某种原因而关闭

假设事件总线上的事件在“非阻塞”庄园中流动。即消息被发布到一个中心主题,如果没有服务正在读取它,则不要堆积在队列中(我试图传达的是一个事件总线,如果事件在总线上发布,它会流“直接通过”而不是排队 - 忽略此时使用的消息传递平台/技术)。这意味着,如果 Inventory 服务关闭了 5 分钟,那么CreateOrderEvent在此期间通过事件总线的 ' 现在“消失”或不被 Inventory 服务看到,因为在我们过于简化的系统中,没有其他系统对那些事件。

那么我的问题是:库存服务(以及整个系统)如何以不丢失/未处理订单的方式恢复状态?

4

3 回答 3

11

好问题!所以这里基本上有三种力量在起作用:

  1. 如果服务出现故障,它可能错过的任何事件都需要重播以保持一致
  2. 这些事件,因为它们发生在“时间”中,有一个“这发生在那个之前”的命令
  3. 可能(但不一定)有另一方有兴趣监督一系列事件以确保达到某个状态。

对于#1 和#2,您都需要某种持久的事件日志。传统的消息队列/主题可能会提供此功能,但您必须考虑消息可能因事务/异常/故障行为而被乱序处理的情况。像 Apache Bookkeeper、Apache Kafka、AWS Kinesis 等更简单的日志可以按顺序存储/保留这些类型的事件,并将其留给消费者按顺序处理/过滤掉重复/分区流等。

对我来说,数字 3 是一台状态机。但是,您实现状态机实际上取决于您。基本上,这个状态机跟踪发生了什么事件,并根据其他系统中的事件转换到允许的状态(并可能参与发出事件/命令)。

例如,当您尝试关闭房屋时,现实世界的用例可能看起来像“托管”。托管公司不仅处理金融交易,通常还与房地产经纪人合作,协调整理文件、签署文件、转账等。每次事件后,托管公司的状态都会从“等待买家签名”改变到“等待卖家签名”到“等待资金”到“关闭成功”......他们甚至有这些事件发生的最后期限,等等,如果资金没有像“交易关闭”那样转移,他们可以转换到另一个状态,未完成”之类的。

您示例中的此状态机将侦听 pub/sub 通道并捕获此状态、运行计时器、发出其他事件以进一步涉及所涉及的系统等。它本身不一定“协调”它们,但它确实跟踪进展并在需要时强制执行超时和补偿。这可以实现为流处理器、流程引擎或(恕我直言最好的起点)只是一个简单的“托管”服务。

实际上,还有更多需要跟踪的内容,例如“托管”服务出现故障/失败时会发生什么,它如何处理重复项,它如何处理给定状态的意外事件,它如何导致重复事件等等......但是希望足以开始。

于 2016-06-10T20:05:10.390 回答
2

我将给出建筑师的答案,而不是深入研究细节。我希望你不要介意。

第一个建议是解耦所有概念:事件、消息、总线和/或队列和异步。这开辟了可能性,前提是您尚未决定使用什么软件来实现您的总线。

从架构的角度来看,如果您需要“必须交付”类型的场景,您将在服务失败时保留消息。是的,当事情发生时,您可能需要对系统进行某种清理,但首先要关注保证交付问题。我看到了两个可以扩展的基本选项(可能还有更多,但这些足以开始考虑问题)。

  • 库存服务处理从队列中提取消息。在此方法中,服务会重新启动并查找任何消息。
  • “公共汽车”保证交货。当出现故障时,它会一直等到服务重新启动(可以 ping 以查看是否再次启动,或者服务可以重新注册为订阅者(企业服务总线类型的场景)。

仅仅因为系统是异步的和基于事件的并不意味着您不能实现某种类型的保证交付。队列是一种选择(您似乎放弃了这个想法?),但是在失败时持续存在并在订阅者再次启动时重试的总线是另一种选择。而且你可以坚持不阻塞。

另一个问题是消息使用什么令牌将它们同步回手头的业务功能,但我假设您已经以某种方式在系统中处理了这个问题。您可能没有的唯一概念是让系统都尊重令牌并尊重其他系统在发生故障时返回消息。

请注意,从业务的角度来看,异步通信并不意味着在接触点上一发不可收拾。您可以返回消息,而无需对每一位信息都使用 asynch 方法。我的意思是库存系统启动可能会处理一条消息并发送到 UI 端的应用程序,它可以返回“忘记它,你太慢了”,因此事务返回到其原始状态(不存在?) .

我没有足够的信息(或时间?)来建议哪种方法最适合您的架构,因为细节仍然有点太高了,但希望这能引起一些思考。

希望这是有道理的,因为我基本上在我的 ADHD 状态下对键盘进行了大脑操作。;-)

于 2016-06-10T18:15:09.530 回答
-1

首先,我们正在构建的系统有一个目的,通常是通过让客户满意和回头客来增加收入和利润。因此,必须处理源自客户行为的消息/事件(假设相关公司正在优先考虑客户体验......因为愿意在其中投资)。

顺便说一句,客户与企业的关系是整个系统中我们想要紧密耦合的关系,与内部的所有其他关系不同。所以在这种情况下,它是“权威”而不是自治的例子。我们保证以品牌为代表的 SLA。

但是消息重要性的范围应该比“必须传递”与否更细粒度,而不是反映优先级。类似于功能变得更细粒度(微服务)。稍后再详细介绍

因此,确保消息/事件被订阅者处理的目标可以通过确保服务永不关闭(如 MS Orleans 中的“虚拟参与者”概念)或通过将更多错误处理逻辑放入传递机制来实现。

后一种选择似乎更加集中/耦合,而不是自主/解耦。但是,如果您假设服务并不总是可用(我们应该这样做),那么您需要考虑删除您对“瞬态”消息的其他假设。

第一个选项将如何保证服务可用性的决定留给拥有服务的敏捷团队,而性能则通过输出指标来衡量。

此外,如果作为封装能力的服务保证了高服务水平(“永不宕机”),那么可以通过调整消息优先级以及将新服务和事件注入到系统。

另一个重要方面是,同步架构(=基于调用堆栈)提供了异步架构(事件驱动)为了减少依赖而没有表现出的三个特性:协调、延续和上下文(参见 Hohpe,“Programming without a调用堆栈”,2006)。

我们仍然需要在业务层面为我们的客户提供这些功能,因此需要在其他地方覆盖它们。Hohpe 建议,松散耦合系统的行为的配置和监控需要额外的代码层,该代码层与核心业务能力一样重要(复杂事件处理以了解事件之间的关系)

这些必须处理大量数据、不同速度、结构和正确性级别的现代 CEP 系统可以在现代数据处理和大数据系统(例如 Spark)之上实现,用于理解、决策和优化敏捷团队(以改善他们的服务)和他们级别的管理团队。

于 2016-07-17T12:00:22.807 回答