zoukankan      html  css  js  c++  java
  • 在微服务领域中处理分布式事务

    今天的每个人都在考虑和构建微服务。从微服务的核心原理和实际情况来看,它是一个分布式系统。

    什么是分布式事务?

    跨网络的多个物理系统或计算机上的事务简称为分布式事务。在微服务领域,事务现在被分发到多个服务中,这些服务被依次调用以完成整个事务。

    下图是一个使用事务的单体电子商务系统:

    在上面的系统中,如果用户向平台发送Checkout请求,则平台将创建在多个数据库表上工作的本地数据库事务,以处理库存中的订单和预留物料。如果任何步骤失败,则事务可以回滚,保留订单和物料。这称为ACID(原子性,一致性,隔离性,耐久性),由数据库系统保证。

    下图是被分解为微服务的电子商务系统:

    分解该系统时,我们创建了具有单独数据库的微服务OrderMicroservice和InventoryMicroservice。当用户发出Checkout请求时,这两个微服务都将被调用以将更改应用到他们自己的数据库中。因为该事务现在通过多个系统跨多个数据库,所以现在将其视为分布式事务。

     微服务中的分布式事务有什么问题?

     随着微服务架构的出现,我们正在失去数据库的ACID性质。事务现在可以跨越多个微服务,因此也可以跨数据库。我们将面临的关键问题是:

    我们如何保持事务的原子性?

    原子性意味着在事务中所有步骤都已完成或都没完成。在上面的示例中,如果InventoryMicroservice方法中的“reserve items”失败,我们如何回滚由OrderMicroservice应用的“process order”更改?

    我们如何处理并发请求?

    如果来自任何一个微服务的对象都同时保留在数据库中,那么另一个请求将读取同一对象。服务应该返回旧数据还是新数据?在上面的示例中,一旦OrderMicroservice完成并且InventoryMicroservice现在正在执行其更新,则客户下达的订单数量请求是否应包括当前订单?

    可能的解决方案

    在设计和构建基于微服务的应用程序时,以上两个问题非常关键。为了解决这些问题,描述了以下方法列表:

    • 两阶段提交(Two-Phase Commit)
    • 最终一致性和补偿(Eventual Consistency and Compensation / SAGA)

    1.两阶段提交

    顾名思义,这种处理事务的方式有两个阶段,即准备阶段和提交阶段。一个重要的参与者是保持事务生命周期的事务协调器(Transaction Coordinator)。

    怎么运行的:

    在准备阶段,所有涉及的微服务都准备提交并通知协调器它们已准备好完成事务。然后在提交阶段,事务协调器向所有微服务发出提交或回滚命令。

    让我们以电子商务系统为例:

    在上面的示例中,当用户发送结帐请求时,TransactionCoordinator将首先开始使用所有上下文信息进行全局事务。首先,它将向OrderMicroservice发送准备命令,以创建订单。然后,它将向库存微服务发送准备命令,以保留物料。当两个服务都可以执行更改时,它们将锁定对象以防止进一步更改,并通知TransactionCoordinator。一旦TransactionCoordinator确认所有微服务都准备好应用其更改,它将通过请求与事务的提交来要求它们保留其更改。此时,所有对象将被解锁。

     

     在失败场景中(上图)-如果在任何时候单个微服务都无法准备,那么TransactionCoordinator将中止事务并开始回滚过程。在该图中,OrderMicroservice由于某种原因未能创建订单,但是InventoryMicroservice已答复它已准备好创建订单。TransactionCoordinator将请求InventoryMicroservice的中止,然后该服务将回滚所做的任何更改并解锁数据库对象。

    优点

      • 该方法保证了交易是原子的。事务将以所有微服务成功或所有微服务均未更改结束。
      • 其次,它允许读写隔离,在事务协调器提交更改之前,对对象的更改不可见。
      • 该方法是同步调用,其中将通知客户端成功或失败。

    缺点

      • 一切都不尽完美,与单个微服务的运行时间相比,两阶段提交的速度相当慢。它们高度依赖事务协调器,事务协调器在高负载下确实会降低系统速度。
      • 另一个主要缺点是锁定数据库行。锁定可能会成为性能瓶颈,并且可能发生死锁,两个事务相互锁定。

    2.最终一致性和补偿

    关于最终一致性的最佳定义之一是在microservices.io上进行了描述:每个服务在更新数据时都会发布一个事件。其他服务订阅事件。收到事件后,服务将更新其数据。

    在这种方法中,分布式事务由相关微服务上的异步本地事务完成。微服务通过事件总线相互通信。

    怎么运行的:

    再次,以电子商务系统为例:

    在上面的示例(上图)中,客户端请求系统处理订单。根据该请求,编排人员将发出一个事件Create Order,以标记事务开始。OrderMicroservice侦听此事件并创建一个订单,如果成功,它将发出一个Order Created事件。编舞人员侦听此事件,并通过发出“ Reserve Items”事件来保留项目。InventoryMicroservice会侦听此事件并保留项目,如果成功,则会发出Items Reserved事件,在此示例中表示交易结束。

    微服务之间的所有基于事件的通信都是通过事件总线发生的,并由另一个系统进行编排以解决复杂性问题。

     如果由于某种原因,InventoryMicroservice未能保留项目(上图),则会发出“无法保留项目”事件。编舞人员侦听此事件,并通过发出Delete Order事件来启动补偿事务。OrderMicroservice侦听此事件并删除创建的订单。

    优点

    这种方法的一大优势在于,每个微服务仅专注于自己的原子事务。如果其他服务需要更长的时间,则不会阻止微服务。这也意味着不需要数据库锁定。由于基于异步事件的解决方案,使用此方法可使系统在重负载下具有高度可伸缩性。

    缺点

    主要缺点是该方法没有读取隔离。这意味着,在上面的示例中,客户可以看到订单已创建,但是在下一秒钟,由于补偿交易,订单被删除。而且,当微服务数量增加时,调试和维护变得更加困难。

    结论

    当由于一个事件而需要在两个位置更新数据时,与两阶段提交相比,最终一致性/ SAGA方法是处理分布式事务的一种更好的方法。主要原因是两阶段提交无法在分布式环境中扩展。最终一致性方法还引入了一系列新问题,例如如何自动更新数据库并发出事件。采用这种方法需要改变开发团队和测试团队的思维方式。

  • 相关阅读:
    USACO第三道题
    uva350 PseudoRandom Numbers
    uva10879 Code Refactoring
    Scrum 冲刺第一篇 晨曦
    WC.exe 晨曦
    [LeetCode 126] 单词梯II(Word Ladder II)
    [LeetCode 129] 根节点到叶子节点数字求和(Sum Root to Leaf Numbers)
    [LeetCode 125] 验证回文(Valid Palindrome)
    [LeetCode 123] 买入与卖出股票的最佳时机III(Best Time to Buy and Sell Stock III)
    [LeetCode 124] 二叉树最大路径和(Binary Tree Maximum Path Sum)
  • 原文地址:https://www.cnblogs.com/crelle/p/13795768.html
Copyright © 2011-2022 走看看