分布式原理-分布式事务

前言

事务是包含一系列操作的一个有边界的工作序列,有明确的开始和结束标志,并且要具备原子性,要么被完全执行,要么完全失败。因此系统做了微服务拆分以后,面临的最大的问题就是如何保证事务的一致性,原先的事务在一个进程中只要保证单进程中的事务性就可以,服务拆分做了分布式以后,就面临着一个事务涉及到多应用节点之间如何保证事务的ACID。分布式事务,就是在分布式系统中运行的事务,由多个本地事务组合而成。

分布式事务主要是解决在分布式环境下,组合事务的一致性问题。实现分布式事务有以下 3 种基本方法:

  • 基于 XA 协议的二阶段提交协议方法;

  • 三阶段提交协议方法;

  • 基于消息的最终一致性方法。

其中,基于 XA 协议的二阶段提交协议方法和三阶段提交协议方法,采用了强一致性,遵从 ACID,基于消息的最终一致性方法,采用了最终一致性,遵从 BASE 理论。

XA二阶段提交

XA 是一个分布式事务协议,规定了事务管理器和资源管理器接口。因此,XA 协议可以分为两部分,即事务管理器和本地资源管理器。为了保证它们的一致性,我们需要引入一个协调者来管理所有的节点,并确保这些节点正确提交操作结果,若提交失败则放弃事务。

两阶段提交协议的执行过程,分为投票(voting)和提交(commit)两个阶段:

1)投票为第一阶段,协调者(Coordinator,即事务管理器)会向事务的参与者(Cohort,即本地资源管理器)发起执行操作的 CanCommit 请求,并等待参与者的响应。参与者接收到请求后,会执行请求中的事务操作,记录日志信息但不提交,待参与者执行成功,则向协调者发送“Yes”消息,表示同意操作;若不成功,则发送“No”消息,表示终止操作。

2)当所有的参与者都返回了操作结果(Yes 或 No 消息)后,系统进入了提交阶段。在提交阶段,协调者会根据所有参与者返回的信息向参与者发送 DoCommit 或 DoAbort 指令:

  • 若协调者收到的都是“Yes”消息,则向参与者发送“DoCommit”消息,参与者会完成剩余的操作并释放资源,然后向协调者返回“HaveCommitted”消息;

  • 如果协调者收到的消息中包含“No”消息,则向所有参与者发送“DoAbort”消息,此时发送“Yes”的参与者则会根据之前执行操作时的回滚日志对操作进行回滚,然后所有参与者会向协调者发送“HaveCommitted”消息;

  • 协调者接收到“HaveCommitted”消息,就意味着整个事务结束了。

下面举个两阶段提交的例子:

两阶段提交

1)第一阶段:订单系统中将与用户 A 有关的订单数据库锁住,准备好增加一条关于用户 A 购
买 10套口罩的信息,并将同意消息“Yes”回复给协调者。而库存系统由于 口罩库存不
足,出货失败,因此向协调者回复了一个终止消息“No”。

2)第二阶段:由于库存系统操作不成功,因此,协调者就会向订单系统和库存系统发送“DoAbort”消息。订单系统接收到“DoAbort”消息后,将系统内的数据退回到没有用户 A 购买 10套口罩的版本,并释放锁住的数据库资源。订单系统和库存系统完成操作
后,向协调者发送“HaveCommitted”消息,表示完成了事务的撤销操作。

两阶段提交的问题主要有下面几种:

  • 同步阻塞问题:二阶段提交算法在执行过程中,所有参与节点都是事务阻塞型的。也就是说,当本地资源管理器占有临界资源时,其他资源管理器如果要访问同一临界资源,会处于阻塞状态。
  • 单点故障问题:基于 XA 的二阶段提交算法类似于集中式算法,一旦事务管理器发生故障,整个系统都处于停滞状态。尤其是在提交阶段,一旦事务管理器发生故障,资源管理器会由于等待管理器的消息,而一直锁定事务资源,导致整个系统被阻塞。
  • 数据不一致问题:在提交阶段,当协调者向参与者发送 DoCommit 请求之后,如果发生了局部网络异常,或者在发送提交请求的过程中协调者发生了故障,就会导致只有一部分参与者接收到了提交请求并执行提交操作,但其他未接到提交请求的那部分参与者则无法执行事务提交。于是整个分布式系统便出现了数据不一致的问题。

三阶段提交

三阶段提交协议(Three-phase commit protocol,3PC),是对二阶段提交(2PC)的改进。为了解决两阶段提交的同步阻塞和数据不一致问题,三阶段提交引入了超时机制和准备阶段。同时在协调者和参与者中引入超时机制。如果协调者或参与者在规定的时间内没有接收到来自其他节点的响应,就会根据当前的状态选择提交或者终止整个事务。

在第一阶段和第二阶段中间引入了一个准备阶段,也就是在提交阶段之前,加入了一个预提交阶段。在预提交阶段排除一些不一致的情况,保证在最后提交之前各参与节点的状态是一致的。3PC 把 2PC 的提交阶段一分为二,这样三阶段提交协议就有 CanCommit、PreCommit、DoCommit 三个阶段。

三阶段提交:
1)CanCommit阶段:协调者向参与者发送请求操作(CanCommit请求),询问参与者是否可以执行事务提交操作,然后等待参与者的响应;参与者收到CanCommit 请求之后,回复 Yes,表示可以顺利执行事务;否则回复 No。
2)PreCommit阶段:协调者根据参与者的回复情况,来决定是否可以进行 PreCommit 操作,如果所有参与者都回复Yes,则所有参与者执行PreCommit,并将Undo 和 Redo信息记录到事务日志中,返回协调者ACK。假如任何一个参与者向协调者发送了“No”消息,或者等待超时之后,协调者都没有收到参与者的响应,就执行中断事务的操作。
3)DoCommit阶段:DoCmmit 阶段进行真正的事务提交,根据 PreCommit 阶段协调者发送的消息,进入执行提交阶段或事务中断阶段。a.发送提交请求。协调者接收到所有参与者发送的 Ack 响应,从预提交状态进入到提交状态,并向所有参与者发送 DoCommit 消息。b.发送中断请求。协调者向所有参与者发送 Abort 请求。事务回滚。参与者接收到 Abort 消息之后,利用其在 PreCommit 阶段记录的 Undo信息执行事务的回滚操作,并释放所有锁住的资源。

下面举个三阶段提交的例子:

第一阶段:协调者发送给订单系统canConfirm?,订单系统检查资源可用。返回消息“Yes”回复给协调者。同时发送给库存系统canConfirm?,库存系统检查资源是否可用,如果可用返回“Yes”。

CanConfirm阶段

第二阶段:检查阶段订单系统和库存系统都返回“Yes”,则同时发给订单系统和库存系统PreCommit请求,订单系统和库存系统对资源进行锁库操作,将操作写到Redo和Undo日志.最后返回ACK。

PreConfirm阶段

第三阶段:如果收到订单系统和库存系统的PreConfirm阶段的ACK后会最后向两个系统发送DoCommit指令,订单系统和库存系统进行实际操作,成功后返回ACK并释放资源锁。
在默认情况下,参与者会自动将超时的事务进行提交,不会像两阶段提交那样被阻塞
住。

DoConfirm阶段

基于消息的最终一致性

2PC 和 3PC 这两种方法,有两个共同的缺点,一是都需要锁定资源,降低系统性能;二是,没有解决数据不一致的问题。基于分布式消息的最终一致性方案的事务处理,引入了一个消息中间件(MessageQueue,MQ),用于在多个应用之间进行消息传递。将需要分布式处理的事务通过消息或者日志的方式异步执行,消息或日志可以存到本地文件、数据库或消息队列中,再通过业务规则进行失败重试。

下面举个例子:

基于消息的最终一致性
  1. 订单系统把订单消息发给消息中间件,消息状态标记为“待确认”。
  2. 消息中间件收到消息后,进行消息持久化操作,即在消息存储系统中新增一条状态为“待发送”的消息。
  3. 消息中间件返回消息持久化结果(成功 / 失败),订单系统根据返回结果判断如何进行
    业务操作。失败,放弃订单,结束(必要时向上层返回失败结果);成功,则创建订单。
  4. 订单操作完成后,把操作结果(成功 / 失败)发送给消息中间件。
  5. 消息中间件收到业务操作结果后,根据结果进行处理:失败,删除消息存储中的消息,结束;成功,则更新消息存储中的消息状态为“待发送(可发送)”,并执行消息投递。
  6. 如果消息状态为“可发送”,则 MQ 会将消息发送给支付系统,表示已经创建好订单,需要对订单进行支付。支付系统也按照上述方式进行订单支付操作。
  7. 订单系统支付完成后,会将支付消息返回给消息中间件,中间件将消息传送给订单系统。订单系统再调用库存系统,进行出货操作。

总结

XA二阶段提交协议 三阶段提交协议 基于分布式消息的最终一致性方案
算法一致性类别 强一致性 强一致性 最终一致性
执行方式 同步执行 同步执行 异步执行
同步阻塞问题
单点故障问题
系统并发度 XA二阶段提交<三阶段提交<分布式消息最终一致性
分布式事务性能 XA二阶段提交<三阶段提交<分布式消息最终一致性
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349