跨微服务的 ACID 事务


大规模分布式系统上的分布式事务被认为本质上是邪恶的,需要按照CAP 定理,为了避免走弯路,请参考:分布式事务可能是个伪概念以及Shopify如何使用Saga等模式实现电子商务:Shopify如何使用Ruby实现每小时销售1亿美元?
本文是atomikos商家自己的宣传文章:
如何跨 REST 微服务实现经典的 ACID 事务?你们中的一些人可能知道我们的TCC用于预订式交互的基于补偿的 REST 事务。它很好而且松散耦合,但它不适合想要使用经典回滚而不是补偿的场景。这篇文章介绍了另一种设计,我们目前在 Atomikos 正在研究这种设计。
我们将在本文的其余部分逐步完善规范,以便更容易理解这些概念。

我们将使用以下角色和职责:
REST 应用程序
想象一个(复合)REST 应用程序:

  • 协调整个工作流程
  • 调用多个参与者服务
  • 通过协调器服务(如下所述)提交(或回滚)所有参与者服务的工作。

参与服务
参与者服务实际上是一个微服务,它:
  • 调用时创建本地 ACID 事务
  • 执行本地数据库工作
  • 在调用结束时保持事务打开,以便 REST 应用程序稍后提交(如下所述)。

协调员服务
协调器服务是一种专门的实用程序服务,用于协调跨多个参与者服务的两阶段提交。它还在发生故障和/或重新启动时执行日志记录和恢复。更多详情如下…
最小用例:一起提交或回滚 REST 微服务
最小用例实际上是在这种情况下可以做的最基本的事情:两个或多个微服务调用一起提交或回滚。它是这样的:
  1. REST 应用程序运行并调用任意数量的参与者服务。
  2. 每个参与者服务返回(作为其响应的一部分)AcidParticipantLink 信息:基本上是可以提交事务的 URI。
  3. REST 应用程序在整个“事务”逻辑中进行时收集所有 AcidParticipantLinks。
  4. REST 应用程序然后要求协调器服务提交(或者,回滚)其工作的所有相关 AcidParticipantLinks

 
更精细的用例:重复调用可以共享相同的锁
前面的场景有效,但同一参与者的重复调用将使用不同的本地 ACID 事务,这意味着他们无法看到/访问数据库中的相同数据。后续调用之间没有锁共享。在某些情况下,这可能是可取的,可以按如下方式完成:
  1. REST 应用程序首次调用参与者服务并返回一个 AcidParticipantLink。
  2. REST 应用程序提取参与者的事务标识符(包含在 AcidParticipantLink 中)。
  3. REST 应用程序现在可以第二次调用参与者服务,并将事务标识符作为调用的参数。
  4. 参与者服务检测现有交易标识符并允许调用“加入”现有交易。

其他一切都像前面的场景一样工作。
 
高级用例:共享数据库中调用者的服务共享锁
在某些情况下,参与者服务可能需要加入存在于调用方的事务,特别是当它们访问某个共享数据库时。详情将在稍后制定,因此请继续查看更多信息!

...