如何在分布式事务中锁定对象

问题描述 投票:0回答:2

我一直在阅读有关微服务和分布式事务的信息。大多数文章都谈论两阶段提交或Saga模式,但没有详细介绍对象如何锁定,因此在事务未完成时其他人无法访问该数据。

如果我有一个客户服务和一个订单服务,并且我发起一个请求来锁定客户资金,直到处理完订单。在分布式系统中,这是如何实现的。

在数据库中,可以显式地锁定一行,然后另一个请求转到并解锁该行,或者通过使用客户表上的锁定字段来实现,该字段是第一个交易将其锁定为锁定的,并且一旦订单完成,它就会返回并将其设置为解锁或清空该行?

[如果有一些带有示例代码的示例会很棒

microservices distributed-transactions
2个回答
0
投票

在微服务世界中,交易边界在服务之内。服务依赖于最终的一致性。因此,在您的示例中,订单服务将发送一个请求(同步或异步,具体取决于应用程序的语义和规模要求),例如从订单y的客户y中减去x的金额]。

客户服务将对交易中的客户记录执行操作,并将响应返回给客户,如成功处理订单z]或处理订单z失败

然后订单服务可以根据收到的响应触发订单的确认/失败过程。

应用程序通常在可用性和ACID强一致性之间进行选择。大多数基于微服务的场景都要求可用性和高可伸缩性,而不是强一致性,这意味着服务之间的通信是异步的,最终实现了一致的状态。

[大多数文章都谈论两阶段提交或Saga模式,但没有详细介绍如何锁定对象,以便其他人无法访问交易未完成时该数据。

2PC被定义为阻塞。这意味着,如果管理2PC事务的事务管理器出现故障,则无法解决2PC。这样,事务管理器就是单点故障。如果确保重新启动失败的事务管理器,那么据说2PC协议也被阻止,则可以确保事务管理器将可用,并且不会阻止该解决方案。

然后2PC使用锁。它们是协议的基本元素。事务管理器与参与者沟通-资源。参与者是数据库。当2PC开始运行时,调用prepare意味着数据库将对参与事务的所有行进行持久锁定。当事务管理器调用commit时,将释放此锁。重要的是要了解2PC之前的事务正在进行中(不是持久性的)。它存储在内存中。在prepare调用之后,它会被永久存储,直到调用commit(此时,该协议可能会被不可用的事务管理器阻止-锁是持久的,没有人可以释放它-aka。我们正在等待事务管理器执行所以)。

这是关于2PC的锁定。但是从数据库角度来看,存在事务锁定。当您更新数据库中的一行时,该事务正在进行中(存储在内存中)。但是数据库可能已经在锁定该行,以便其他更新不会同时发生。在这种情况下,大多数数据库都不会锁定行,因为它们使用快照隔离(MVCC,https://en.wikipedia.org/wiki/Snapshot_isolation)。这特别意味着该行被乐观地锁定,并且数据库允许其他事务更新该行。

但是2PC准备不能被乐观地处理。当数据库对事务管理器的准备请求答复“ OK”时,该行被锁定。而且您无法手动管理此锁定。如果这样做,将破坏2PC的一致性保证。

在您的示例中,有一个客户服务和一个订单服务。当2PC事务跨越两个服务时。然后,客户更新数据库,而定单服务也更新数据库。数据库中仍在运行中的事务中。然后请求完成,事务管理器命令正在进行的事务提交。它运行2PC。它在客户服务数据库事务上调用prepare,然后在订单服务事务上调用,然后调用commit。

如果使用英雄传奇模式,则英雄传奇跨越两个服务。但是客户服务会在运行中创建数据库,并立即将其提交。然后,呼叫转到订单服务,再次发生相同的情况。当请求完成时,传奇检查一切正常。如果不是,则调用补偿回调。

失败就是“麻烦”。对于传奇,您需要在回调方法中自行维护故障解决方案。对于2PC,故障解决是通过回滚调用自动处理的。

[注:我试图在此处总结2PC:https://developer.jboss.org/wiki/TwoPhaseCommit2PC我不确定该解释是否足够容易理解,但您可以尝试进行检查。您可能会让我知道错误解释的地方。谢谢。


0
投票

[大多数文章都谈论两阶段提交或Saga模式,但没有详细介绍如何锁定对象,以便其他人无法访问交易未完成时该数据。

© www.soinside.com 2019 - 2024. All rights reserved.