8

我们有 7 个微服务通过事件总线进行通信。我们有一个实时交易序列:

服务 1->service2->service3(依此类推。)直到交易被视为完成

我们必须确保所有交易都发生。

当然,我们可以在任何时候失败。因此,我们正在考虑将“半生不熟”的交易重播到完成的机制。

它变得棘手。我们想到了两种方法:

  1. 拥有另一个服务(主管服务),它将以我们的实时序列记录每个部分,并且在事务未完成(超时)时足够聪明,以了解我们如何从左点继续

    缺点:一个中央服务上有很多“智能”逻辑

  2. 在每项服务上都有重试机制,同时每个服务都照顾自己并重播自己的服务,直到成功或用尽

    缺点:在每个服务上重试重复的代码很多

各位专家怎么看?

感谢

4

2 回答 2

9

您似乎在谈论的是如何处理分布式架构中的事务。

这是一个广泛的话题,可以写整本书。您的问题似乎只是关于重试事务,但我相信仅此一项可能不足以解决分布式事务工作流的问题。

我相信您可能会受益于对以下概念的更多理解:

补偿交易背后的想法是每个 ying 都有其 yang:如果您有一个可以下订单的交易,那么您可以通过取消订单的交易撤消它。后一种交易是补偿交易。因此,如果您执行了许多成功的交易,然后其中一个失败了,您可以追溯您的步骤并补偿您所做的每笔成功交易,从而恢复它们的副作用。

我特别喜欢REST from Research to Practice一书中的一章。它的第 23 章(Towards Distributed Atomic Transactions over RESTful Services)深入解释了Try/Cancel/Confirm 模式

一般而言,这意味着当您进行一组事务时,它们的副作用在事务协调器确认它们都成功之前不会生效。例如,如果您在 Expedia 上进行预订,并且您的航班有两条航程与不同的航空公司,那么一笔交易将预订美国航空公司的航班,另一笔交易将预订美国联合航空公司的航班。如果您的第二次预订失败,那么您想补偿第一次。但不仅如此,您要避免第一次预订有效,直到您能够确认两者。因此,初始交易进行预订,但保留其副作用等待确认. 第二个保留也会做同样的事情。一旦事务协调器知道所有内容都已保留,它可以向所有各方发送确认消息,以便他们确认他们的保留。如果在合理的时间窗口内未确认预订,受影响的系统会自动取消预订。

《企业集成模式》这本书有一些关于如何实现这种事件协调的基本思想(例如,参见流程管理器模式并与路由滑动模式进行比较,这与微服务世界中的编排与编排的想法相似)。

如您所见,能够补偿交易可能会很复杂,具体取决于您的分布式工作流程的复杂程度。流程管理器可能需要跟踪每个步骤的状态,并知道何时需要撤消整个事情。这几乎就是微服务世界中Sagas的想法。

《微服务模式》这本书有一整章叫做用 Sagas 管理事务,详细介绍了如何实现这种类型的解决方案。

我通常还考虑的其他一些方面如下:

幂等性

我相信在分布式系统中成功实现服务事务的关键在于使它们具有幂等性。一旦你可以保证给定的服务是幂等的,那么你就可以安全地重试它,而不必担心会导致额外的副作用。但是,仅重试失败的事务并不能解决您的问题。

瞬态与持久性错误

在重试服务事务时,您不应该只是因为它失败而重试。您必须首先知道它失败的原因,并根据错误重试或不重试是否有意义。某些类型的错误是暂时的,例如,如果一个事务由于查询超时而失败,那么重试可能很好,并且很可能第二次会成功;但是如果你得到一个违反数据库约束的错误(例如,因为一个 DBA 给一个字段添加了一个检查约束),那么重试这个事务是没有意义的:无论你尝试多少次它都会失败。

接受错误作为替代流程

在服务间通信(计算机到计算机交互)的情况下,当您的工作流的给定步骤失败时,您不一定需要撤消您在前面的步骤中所做的一切。您可以将错误作为工作流程的一部分。对可能的故障原因进行分类,并使它们成为仅需要人工干预的替代事件流。这只是完整编排中的另一个步骤,需要一个人进行干预以做出决定,解决与数据的不一致或只是批准走哪条路。

例如,可能在您处理订单时,支付服务失败,因为您没有足够的资金。因此,撤消其他所有内容是没有意义的。我们所需要的只是将订单置于某个问题解决者可以在系统中解决它的状态,一旦修复,您就可以继续工作流程的其余部分。

事务和数据模型状态是关键

我发现这种类型的事务工作流需要对模型必须经历的不同状态进行良好的设计。与 Try/Cancel/Confirm 模式的情况一样,这意味着最初应用副作用而不必使数据模型对用户可用。

例如,当您下订单时,您可能会将其以“待处理”状态添加到数据库中,该状态不会出现在仓库系统的 UI 中。确认付款后,订单将显示在 UI 中,以便用户最终处理其发货。

这里的困难在于发现如何设计事务粒度,即使您的事务工作流程的一个步骤失败,系统仍处于有效状态,一旦故障原因得到纠正,您就可以从该状态恢复。

为分布式事务工作流设计

因此,如您所见,设计以这种方式工作的分布式系统比单独调用分布式事务服务要复杂一些。现在,每个服务调用都可能由于多种原因而失败,并使您的分布式工作流处于不一致的状态。重试事务可能并不总能解决问题。并且您的数据需要像状态机一样建模,以便应用副作用但直到整个编排成功后才确认。

这就是为什么整个事情可能需要以不同于您通常在单体客户端-服务器应用程序中所做的方式设计的原因。在解决冲突时,您的用户现在可能是设计解决方案的一部分,并且考虑到事务编排可能需要数小时甚至数天才能完成,具体取决于他们的冲突解决方式。

正如我最初所说,这个话题太宽泛了,可能需要一个更具体的问题来详细讨论这些方面的一两个方面。

无论如何,我希望这对您的调查有所帮助。

于 2018-01-06T22:57:52.270 回答
0

据我所知(您可能也已经知道),您似乎正在尝试实现断路器模式,以及是否将其实现为中央服务或业务事务逻辑的一部分。

决定是否将其作为单独的服务更好的一个参数是查看您是否只有一个这样的事务或还有更多?如果不止一个,那么最好将断路器从您的实际业务中撤出。它可以是包含在不同服务或独立微服务中的一种实用程序组件。在独立服务的情况下,可以选择使用现成的产品/库/框架来执行此操作。我不太了解您的环境和限制,但您甚至可以考虑为此目的使用 Camel 或轻型 BPM 引擎之类的东西。

在我看来,将这种非业务逻辑与您的实际事务业务分开会更好,无论是作为作为库添加的实用程序组件还是单独的服务。

于 2017-12-22T10:32:08.763 回答