如何在事件驱动微服务中创建重放机制

ray*_*man 8 java architecture transactions event-driven-design microservices

我们有7个微服务通过eventbus进行通信.我们有一个实时的交易顺序:

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

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

当然,我们可以在任何时候出现失败.因此,我们正在考虑将机制设备重播为"半成品"交易.

这变得棘手.我们考虑的两种方式:

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

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

  2. 每个服务都有重试机制,而每个服务都有自己的服务,并重播它自己直到成功或被解雇

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

你有什么专家的想法?

谢谢

Edw*_*rzo 7

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

这是一个广泛的主题,可以写整本书来讨论这个问题。您的问题似乎只是关于重试事务,但我认为仅凭这一点可能不足以解决分布式事务工作流的问题。

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

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

我特别喜欢REST from Research to Practice一书中的一章。它的第 23 章(基于 RESTful 服务的分布式原子事务)深入解释了Try/Cancel/Confirm 模式

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

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

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

《微服务模式》一书有一整章名为“使用 Sagas 管理事务”,其中详细介绍了如何实现此类解决方案。

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

幂等性

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

瞬态与持久性错误

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

接受错误作为替代流程

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

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

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

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

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

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

设计分布式事务工作流

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

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

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

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