微服务架构分布式事务解决方案

前言

什么是微服务?微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务内聚不同的业务模块。但是这样的分布式架构风格存在事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上,导致系统的一致性(Consistency)、可用性(Availability)、分区容错(Partition-tolerance)难以实现。

今天我们就来了解一下,微服务架构的分布式事务的解决方案

分布式事务概述

在这里插入图片描述
普通的单机事务,一个服务连接一个数据库,进行一系列数据操作和事务管理,也称为本机事务。
在这里插入图片描述
分布式事务-夸库事务,通过夸库产生了多个节点的事务,出现了无法统一管理的问题。
在这里插入图片描述
分布式事务-微服务。微服务多个服务之间分别连接不同节点的数据库,服务与服务之间调用也是无法控制服务之间的事务问题。如果中间某个过程出现了问题,就会出现数据不一致。

XA/JTA规范

两阶段提交(2PC)
两阶段提交是通过引入协调者,由协调者来判断最终事务是否真正提交。

第一次prepare阶段,各个参与者向协调者发起预提交的请求。由协调者来做出提交是否成功的判断,如果所有参与者全部预提交成功了,才可进行commit阶段,如果出现其中一个参与者没有成功,则协调者发送通知,让参与者进行回滚事务。

第二次commit阶段,当prepare阶段所有参与者全部预提交成功后。协调者通知参与者提交事务,当然前者没有全部成功的情况下,通知参与者回滚事务也是在这一个阶段

XA/JTA规范的两阶段提交所存在的隐患

  • 太过保守:在提交事务的时候任意一个节点失败就会导致,整个事务的失败,没有完善容错性。
  • 同步阻塞问题:XA/JTA规范的两阶段提交在预提交的时候会锁住数据库里面的资源,当出现其他操作此数据的事务时,都处于同步阻塞的状态,无法进行操作
  • 数据一致性:在commit阶段由于网络原因或者其他原因导致其中一个参与者提交失败。就会产生数据不一致性

由这些隐患可以看出来,所谓的分布式事务并不能像本机事务那样做到完美的数据一致性。它只是尽可能的解决了99%的事务问题,还是会出现一些偶发情况导致数据的一致性问题。XA/JTA的两阶段提交分布式事务只能通过binlog日志,查看问题采取人工回滚事务来解决问题。
在这里插入图片描述

柔性事务

CAP理论

开发大规模的分布式系统时会遇到三个特性:一致性(Consistency)、可用性(Availability)、分区容错(Partition-tolerance),而一个分布式系统最多只能满足其中的两项。
分区容错性是分布式系统必然需要面对和解决的问题,因此系统架构师往往需要把精力花在如何根据业务特点在C(一致性)和A(可用性)之间寻求平衡。而前面我们提到的JTA 两阶段提交协议的分布式事务方案,强调的就是一致性;由于可用性较低,实际应用的并不多。

BASE理论

基本可用(Basically Available)
指分布式系统在出现不可预知故障的时候,允许损失部分可用性。

软状态( Soft State)
指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。

最终一致( Eventual Consistency)
强调的是所有的数据更新操作,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

最大努力通知方案

最简单的一种柔性事务,适用于一些最终一致性时间敏感度低的业务,且被动方处理结果不影响主动方的处理结果。典型的使用场景:一些短信通知类需求功能方面,并且不影响主动方处理结果的场景。例如银行通知、商户通知等
在这里插入图片描述

TCC两阶段补偿型方案

两阶段补偿型方案Try-Confirm-Cancel简称为TCC,属于应用层的一种补偿型方案

Try阶段
完成所有业务检查(一致性),预留业务资源(准隔离性)

Confirm阶段
确认执行业务做确认提交操作,不做任何业务检查, 只使用Try阶段全部成功预留的业务资源。默认:Confirm阶段是不会出错的,即:只要try成功了,Confirm阶段就基本上不会出现失败,当然也存在失败的可能。就像我们上文所说,分布式事务并不能完美的解决事务问题,只是尽可能达到99%的解决事务问题。在这里我们就认为是成功的。

Cancel阶段
主要是在业务执行错误时取消Try阶段预留的业务资源。

在这里插入图片描述
举一个例子吧,A向B转账,系统中业务逻辑思路大概是图中应用层部分

  1. 在try阶段中,先调用银行的远程接口,冻结A和B的金额。对业务中需要操作的资源进行预留
  2. 在经过自己系统中的一系列的业务逻辑处理后开始进行Confirm阶段,执行远程接口转账操作。等转账成功进行取消冻结操作。
  3. Cancel阶段则第二步成功,则转账成功,若第二步失败,则转账失败调用远程接口进行资金解冻,解除try阶段的对资源的冻结

问题来了:当Confirm中一个节点出现失败,另一个确认提交成功了之后同样会出现数据一致性问题。该如何解决
由于这是补偿型方案,所以需要程序员写一些补偿代码,例如本机的链接数据库操作的话,可以记录一下失败原因日志或者sql执行时失败的sql,在补偿方案中进行对其失败信息进行解析并且进行数据回滚,来达到数据一致性。记录一些错误日志,若出现系统没办法补偿回滚的数据,还需要人工去进行数据的回滚。

柔性事务TCC和强一致性事务XA/JTA的区别

TCC与XA/JTA对比

  1. XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。会产生同步阻塞问题,其他事务访问此数据需要等待其完成才可以进行操作。而TCC是业务层面的分布式事务,实现最终一致性。他只是对资源的占用,并不会锁住资源,其他资源当检出资源被占用,就会返回数据结果,此资源被占用,而不会阻塞在那里等待
  2. TCC跟XA的2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些
  3. XA中没有完善的容错机制,错了就是错了,而TCC中是有相应的补偿机制,可以挽救一些错误的提交信息
  4. XA中协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待状态,无法完成其它操作。TCC处于应用层,不会出现阻塞问题。

TCC的开源框架实现

Atomikos,tcc-transaction,spring-cloud-rest-tcc,支付宝tcc

可靠消息最终一致性方案

在这里插入图片描述
基于普通的消息队列中间件做的解决方案。也是采用的两阶段提交的方案形式,使用数据中间状态和独立的消息服务,来作为数据协调者,具体执行操作我们来举个例子,相信大家就能够明白了。

下单的业务场景:1.减库存 2.生成订单 接下来我们就使用普通mq的方式保证这两部的事务,达到最终数据一致性
1.prepare阶段,发送初始化减库存消息到独立消息服务中并且把订单号传过去,保证后续的状态确认(也就是最后的定时消息状态确认那步)有查询依据,消息服务并不是直接发送消息到mq去操作减库存,而是记录一个状态为init

第一阶段结束后进行系统的业务逻辑,去生成订单数据。

2.confirm阶段,发送确认消息到消息服务中,将记录状态改为send状态。只有状态为send状态下才发送消息到消息队列,消费者接收到消息,去做减库存的操作,当减库存成功之后进行回调消息服务,修改当前消息的状态为end状态

说明:
消息队列一般情况下都会是部署高可用的mq,消息队列的失败原因暂且忽略。首先是prepare阶段出错。那么直接返回错误信息,不会出现数据不一致的情况。

当在confirm阶段出错,就会出现数据不一致的问题,在这里补充一下,消息服务中的状态有(init,send,end)当消息服务中的定时任务检查到状态不是end状态的数据,就会去调用订单服务中的接口,通过第一阶段传过去的订单号查询数据库,或者缓存中是否存在这个订单,如果存在,则放弃整个流程的操作,删除这条订单,进行回滚。从而保证了数据的最终一致性。

当在减库存的服务中出现问题,也会出现数据不一致的问题。但是回调函数就不会去执行修改状态的回调函数,当定时任务开始检查时同样会检查到消息没有完成,并且去查询订单表中数据是否存在,存在则删除。

总结

分布式解决方案中还有一个使用RocketMQ的最终一致性方案,由于原理大概相同,只是用法上有些不同,在这里就没有拿出来讲,在这里总结了四个解决方案,各有各的优点,各有各的缺点,我认为在不同的场景,应用不同的解决方案灵活使用,是可以带来更大的优化程度的。当然,可能还会有更好的一些解决方案或者基于这些方案中的一些补偿,希望小伙伴们可以多多分享一下,互相学习一下。希望这篇文章能够帮助到大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值