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



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

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

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

当然,我们随时都可能失败。因此,我们正在考虑使用机制来重播"半生不熟"的交易完成。

它变得越来越棘手。我们思考的两种方式:

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

    弊: 一个中央服务上的许多"智能"逻辑

  2. 在每个服务上都有重试机制,而每个服务都照顾好它自己并重放它自己的,直到成功或流露出来

    弊: 每个服务上的大量重试重复代码

各位专家怎么看?

谢谢

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

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

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

  • 补偿事务模式
  • 尝试/取消/确认模式
  • 长时间运行的事务
  • 传说

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

我特别喜欢《从研究到实践的REST》一书中的一章。它的第23章(通过RESTful服务迈向分布式原子事务)深入解释了尝试/取消/确认模式

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

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

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

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

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

幂等性

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

暂时性错误与持续性错误

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

将错误作为替代流

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

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

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

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

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

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

设计分布式事务工作流

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

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

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

无论如何,我希望这在某种程度上对您的调查有所帮助。

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

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

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

最新更新