【问题标题】:How to rollback MicroServices如何回滚微服务
【发布时间】:2020-01-30 09:00:14
【问题描述】:

我对微服务有疑问。假设有 5 个微服务,比如 M1、M2、M3、M3、M4 和 M5。有 4 个数据库由 4 个微服务连接/访问。 比如M2连接MySQL,M3连接Cassandra,M4连接MongoDB,M5连接Oracle。

现在

Step-1: M1调用M2更新MySQL中的一些用户数据,更新成功,最后得到M2的成功响应

Step-2: M1 调用 M3 更新 Cassandra 中的一些数据,更新成功,最后得到 M3 的成功响应

第 3 步: M1 调用 M4 以更新 MongoDB 中的一些数据,但由于某些 DB 服务器问题或任何其他问题而失败。

我的要求是,我想回滚以前微服务(M2 和 M3)发生的数据库更改

我们应该怎么做才能实现这种回滚场景?

【问题讨论】:

    标签: spring-boot microservices


    【解决方案1】:

    这是分布式事务的典型案例。无论您对数据库使用单独的技术还是在不同的服务器上使用相同的技术,您都执行事务性操作。 为了处理该类型事务的回滚,您不能依赖数据库技术机制来处理事务和回滚。你必须自己做。

    传奇模式

    微服务架构中分布式事务场景的常见解决方案是Saga pattern。 分布式 sagas 是一种在您所描述的场景中管理故障的模式。

    Saga 是根据业务流程创建的,例如“在网上商店购买产品”。此过程可能涉及对多个微服务的多个操作。 Saga 将控制和管理此流程的执行,如果其中一个步骤失败,它将触发操作以恢复在失败操作之前完成的操作。

    有多种方法可以实现 saga。这取决于您的架构和微服务相互通信的方式。你使用命令和/或事件吗?


    示例

    “在网上商店购买产品”业务流程。假设这个业务流程有 3 个简单的步骤,由 3 个不同的微服务完成:

    • 操作 1 - 在 products-inventory-micro-service 中保留产品
    • 操作 2 - 在支付微服务中验证支付
    • 操作 3 - 在订单微服务中订购产品

    使用事件:

    您可以发布事件以执行某些操作(或操作),如果其中一个操作失败,您可以发布该事件的恢复(或删除)事件。对于上述业务流程,让我们说 1. 操作成功和 2. 操作失败。在这种情况下,为了回滚 1. 操作,您将发布一个类似“RemoveReservationFromProduct”的事件,以便删除保留并将状态恢复到该业务流程的事务开始之前的状态。此事件将由事件处理程序获取,该事件处理程序将在您的数据库中恢复该状态。由于它是一个事件,因此您可以针对失败实现重试机制,或者如果代码中存在一些错误,则稍后重新应用它。

    使用命令:

    如果您使用某种 REST API 作为命令直接调用您的微服务,您可以运行一些删除或更新端点来恢复您所做的更改。对于上述业务流程,让我们说 1. 操作成功和 2. 操作失败。在这种情况下,为了回滚 1. 操作,您将调用删除 api 来删除特定产品的预留,以便删除预留并将状态恢复到该业务流程开始之前的状态.

    您可以查看this 示例如何实现 Saga 模式。

    【讨论】:

    • 我是微服务新手,当手动回滚事务时,说动作 2 失败了,现在我们必须回滚动作 1,但现在在删除动作 1 的网络出现故障时,我们将如何处理此类场景。
    • 通常在开发 sagas 时,你有某种“Saga Orchestrator”。这个组件或类是控制整个 Saga 操作并保持每一步状态的组件。它通常会有一些重试策略。因此,如果“操作 2”因某些网络问题而失败,它将确保它重试该操作几次。如果仍然失败,编排器可以延迟重试。如果仍然失败,您可以将 Interanl Saga 状态设置为:RevertingFailed,然后手动重新访问。根据 orcestrator 的聪明程度,这种状态应该在极少数情况下发生。
    • 在其中一个视频中浏览一些 saga 模式的 youtube 视频时,据说我们可以使用 kafa 来存储消息以防网络故障。我正在浏览kafka视频。
    【解决方案2】:

    为了回答您的问题,让我们添加一些业务需求

    案例 1。 M1 正在根据收到的事件(如已下订单)与其他微服务进行所有交互

    现在在这种情况下 M2 ... M5 更新,

    要求1:如果它们都相互独立。

    首先从一个事件创建 5 个事件,然后

    在这种情况下,您可以将此事件添加到表中,将此事件标记为未处理,并且某些计时器会读取未处理的事件并尝试以幂等方式执行所有任务,如果此类任务失败并且您的团队可以检查它们并手动解决它们。

    (您可以通过使用故障转移队列来实现类似的逻辑 - 在一段时间后将相同的事件发送回原始队列)

    要求2:如果所有都不独立

    使用单个事件并且仍然是相同的解决方案。

    在上述解决方案中,主要好处是即使您的系统在事务之间重新启动,您最终仍将拥有一致的系统

    案例2.如果调用了M1 api,M1需要完成多个微服务的所有任务,然后响应用户。

    我们可以在 M1 微服务数据库 (sync_event_table) 中创建一个启动事件 尝试在所有微服务中进行更新 全部完成后,用完成更新同步事件表

    对于那些未完成的情况 - 运行一个计时器来检查未完成 > X 分钟的作业,然后执行撤消操作或任何需要的操作。

    本质:

    因此,如果您看到所有解决方案都建议您的系统调整所有差异。微服务更新

    通过创建工作

    检查作业状态

    编写撤消/重做作业功能

    【讨论】:

      【解决方案3】:

      据我了解,Saga 是您正在寻找的。 这个想法是为每个状态更改操作提供一个撤消操作,如果下游出现问题,则必须调用它。

      【讨论】:

      • 这是你的答案^^
      【解决方案4】:

      您可以确保在整个调用序列中启用了@Transactional。

      1. 考虑从 M1 调用所有微服务作为单个事务。
      2. 以下列方式公开回滚:
        • 在 M2、M3 和 M4 中更新 DB 时,将值同时放入 Spring 缓存中 与 DB。
        • 在 M2、M3 或 M4 中调用 /rollback 时,从 Spring Cache 获取值并撤消 来自 DB。
      3. 在hysterix命令的fallbackMethod中,当M1回复错误或一些默认输出时,调用其他服务的/rollback。

      这可能不是一个完美的解决方案,因为它引入了另一个故障点作为 /rollback 处理,但可以实现最快的一个。

      【讨论】:

        猜你喜欢
        • 2015-12-08
        • 2020-10-29
        • 2018-02-21
        • 2020-07-05
        • 2022-10-12
        • 2014-01-08
        • 1970-01-01
        • 2021-12-13
        • 2018-01-15
        相关资源
        最近更新 更多