(最高版本)分布式事务

197 阅读11分钟

库存和订单的协调:

先查询订单,是否满足要求,如果满足下单要求,锁定号源资源,执行挂号,生成订单;如果失败,执行退号和取消订单(订单的生成设计到金额的结算)

如何防止重复挂号:每次下单,执行到,redis上会存入用户所挂的医院科室,有效时间未1m,只有再挂号

挂号如何防止订单重复提交:再第一次执行挂号的时候,会插入本人的证件号,和医院科室号,只有在挂号后,才可以删除;

挂号前先检测redis,有token(有效时间20秒),进入订单检查,是否符合下单条件,符合执行挂号,生成订单,有异常,回滚,删除redis中的token

分布式的订单和库存系统如何处理事务问题,

分布式系统事务

实现方案 2pc

3pc

TCC

可靠消息最终一致

最大努力通知

一.最大努力通知方案的实现

   1.业务活动的主动方,在完成业务处理之后,向业务活动的被动方发送消息,允许消息丢失。
   2.主动方可以设置时间阶梯型通知规则,在通知失败后按规则重复通知,直到通知N次后不再通知。
   3.主动方提供校对查询接口给被动方按需校对查询,用于恢复丢失的业务消息。
   4.业务活动的被动方如果正常接收了数据,就正常返回响应,并结束事务。
   5.如果被动方没有正常接收,根据定时策略,向业务活动主动方查询,恢复丢失的业务消息。
   

二.最大努力通知方案的特点 1.用到的服务模式:可查询操作、幂等操作。

2.被动方的处理结果不影响主动方的处理结果;

2.适用于对业务最终一致性的时间敏感度低的系统;

3.适合跨企业的系统间的操作,或者企业内部比较独立的系统间的操作,比如银行通知、商户通知等;

两阶段提交(2PC)(强一致、中心化的原子提交协议)

组成:

是中心化协调者节点:协调整体的事务

参与者节点:对请求处理端的服务

2pc分为两阶段:

阶段一:协调者收到发来的请求,发送预处理请求给其他服务,替他服务执行事务,处于umcommint状态。如果参与节点都返回yes或no

阶段二:如果一阶段的参与节点返回yes,协调者发送commot请求给各个节点,各节点提交事务 如果有任意一个节点返回no,发送回滚请求,各节点回滚数据。

2PC缺点:

性能问题:论是在第一阶段的过程中,还是在第二阶段,所有的参与者资源和协调者资源都是被锁住的,只有当所有节点准备完毕,过程会比较漫长,对性能影响比较大。

2PC出现单点问题的三种情况

(1)协调者正常,参与者宕机

由于 协调者 无法收集到所有 参与者 的反馈,会陷入阻塞情况。

解决方案:引入超时机制,如果协调者在超过指定的时间还没有收到参与者的反馈,事务就失败,向所有节点发送终止事务请求。

(2)协调者宕机,参与者正常

无论处于哪个阶段,由于协调者宕机,无法发送提交请求,所有处于执行了操作但是未提交状态的参与者都会陷入阻塞情况.

解决方案:引入协调者备份,同时协调者需记录操作日志.当检测到协调者宕机一段时间后,协调者备份取代协调者,并读取操作日志,向所有参与者询问状态。

(3)协调者和参与者都宕机

发生在第一阶段: 因为第一阶段,所有参与者都没有真正执行commit,所以只需重新在剩余的参与者中重新选出一个协调者,新的协调者在重新执行第一阶段和第二阶段就可以了。

3pc

分为:CanCommit阶段、PreCommit阶段、DoCommit阶段

和2pc不同的是,在CanCommit阶段,会 尝试获取数据库锁 ,2/3阶段和2pc相同

3pc还增加了参与节点的连接超时的功能,方式参与节点长时间阻塞

2pc的方案:

1、XA方案(数据层2pc)

数据库提供了2pc接口协议来实现分布式事务

以上三个角色之间的交互方式如下 :

AP(Application Program) : 既应用程序,可以理解为使用DTP分布式事务的程序。

RM(Resource Manager) : 即资源管理器,可以理解为事务的参与者,一般情况下是指一个数据库实例,通过资源管理器对该数据库进行控制,资源管理器控制着分支事务(附着于ap上)

TM(Transaction Manager) : 事务管理器,负责协调和管理事务,事务管理器控制着全局事务,管理事务生命周期,并协调各个RM。全局事务是指分布式事务处理环境中,需要操作多个数据库共同完成一个工作,这个工作即是一个全局事务

DTP模型定义TM和RM之间通讯的接口规范叫XA,简单理解为数据库提供的2PC接口协议,基于数据库的XA协议来实现2PC又称为XA方案。

总结: 整个2PC的事务流程涉及到三个角色AP、RM、TM。AP指的是使用2PC分布式事务的应用程序;RM指的是资源管理器,它控制着分支事务;TM指的是事务管理器,它控制着整个全局事务。

1)在准备阶段RM执行实际的业务操作,但不提交事务,资源锁定;

2)在提交阶段TM会接收RM在准备阶段的执行回复,只要有任一个RM执行失败,TM会通知所有RM执行回滚操作,否则,TM将会通知所有RM提交该事务。提交阶段结束资源锁释放。

XA方案的问题 :(数据层2pc)

1、需要本地数据库支持XA协议。

2、资源锁需要等到两个阶段结束才释放,性能较差。

seata方案

(数据层2pc)(主要的特点:使用了中间键连接数据库,seata不来特定的数据库;第一阶段就提交了数据,并记录undo——log,第二阶段通过读取或删除undo_log来实现事务的确认或回滚,这样,在第一阶段就可以释放事务资源,提高程序的性能)

Transaction Coordinator(TC):事务协调器,它是独立的中间件,需要独立部署运行,它维护全局事务的运行状态,接收TM指令发起全局事务的提交与回滚,负责与RM通信协调各个分支事务的提交或回滚。

Transaction Manager(TM):事务管理器,TM需要嵌入应用程序中工作,它负责开启一个全局事务,并最终向TC发起全局提交或全局回滚的指令。

Resource Manager(RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器TC的指令,驱动分支(本地)事务的提交和回滚。

具体的执行流程如下 :

1、用户服务的TM向TC申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的XID。

2、用户服务的RM向TC注册分支事务,该分支事务在用户服务执行新增用户逻辑,并将其纳入XID对应全局事务的管辖。

3、用户服务执行分支事务,向用户表插入一条记录。 逻辑执行到远程调用积分服务时(XID在微服务调用链路的上下文中传播)。积分服务的RM向TC注册分支事务,该分支事务执行增加积分的逻辑,并将其纳入XID对应全局事务的管辖。

4、积分服务执行分支事务,向积分记录表插入一条记录,执行完毕后,返回用户服务。

5、用户服务分支事务执行完毕。

6、TM向TC发起针对XID的全局提交或回滚决议。

7、TC调度XID下管辖的全部分支事务完成提交或回滚请求。

seata评价: 架构层次方面,传统2PC方案的RM实际上是在数据库层,RM本质上就是数据库自身,通过XA协议实现,而Seata的RM是以jar包的形式作为中间件层部署在应用程序的这一侧的。 两阶段提交方面,传统2PC无论第二阶段的决议是commit还是rollbcak,事务性资源的锁都要保持到Phase2完成才释放。而Seata的做法是在Phase1就将本地事务提交,这样就可以省去Phase2持锁的时间,整体提高效率。

要点说明 : 1、每个RM使用DataSourceProxy连接数据库,其目的是使用ConnectionProxy,使用数据源和数据连接代理的目的就是第一阶段将undo_log和业务数据放在一个本地事务提交,这样就保存了只要有业务操作就一定有undo_log.

2、在第一阶段undo_log中存放了数据修改前和修改后的值,为事务回滚作好准备,所以第一阶段完成就已经将分支事务提交,也就释放了锁资源。

3、TM开启全局事务开始,将XID全局事务id放在事务上下午中,通过feign调用也将XID传入下游分支事务,每个分支事务将自己的Branch ID分支事务ID与XID关联。

4、第二阶段全局事务提交,TC会通知各个分支参与者提交分支事务,在第一阶段就已经提交了分支事务,这里各个参与者只需要删除undo_log即可,并且可以异步执行,第二阶段很快可以完成。

5、第二阶段全局事务回滚,TC会通知各个分支参与者回滚分支事务,通过XID和Branch ID找到相应的回滚日志,通过回滚日志生成反向的SQL并执行,以完成分支事务回滚到之前的状态,如果回滚失败则会重试回滚操作。

TCC方案(TCC是应用层的2PC(2 Phase Commit, 两阶段提交))

	 1.TCC方案属于两阶段型的分布式事务方案,也属于补偿型的分布式事务方案;

	2.用到的服务模式:TCC操作、幂等操作、可补偿操作、可查询操作;

   3.强隔离性、严格一致性、实时性高,适用于对业务要求比较高的场景,比如处理账户、收费等业务;

   4.不与具体的服务框架耦合,在RPC架构中通用;

   5.位于业务服务层而非资源层,TCC方案的出现正是为了解决应用拆分带来的跨应用业务操作原子性的问题;

   6.可以灵活选择业务资源的锁定粒度;

   7.TCC里对每个服务资源操作的是本地事务,数据被lock的时间短,可扩展性好,可以说是为独立部署的SOA服务而设计的;

   8. TCC的Try、Confirm和Cancel操作功能需业务提供,开发成本高。

Hmily方案(tcc的实现方案)

最大努力通知

可靠消息最终一致性方案

是指当事务发起执行完全本地事务后并发出一条消息,事务参与方(消息消费者)一定能够接收消息并处理事务成功,这个方案强调的是事务的参与方达到最终的一致性。

实现方案: 1、本地消息表方案:

将发送消息的日志写到本地,通过本都的事务控制日志信息,通过轮询日志数据,将数据发送到消息队列,消息,mq的数据为了保证能发送到消费端,使用ack的确认机制,保证数据能到达消费端。

2、RocketMQ事务消息方案

RocketMQ事务消息设计则主要是为了解决Producer端的消息发送与本地事务执行的原子性问题

而RocketMQ本身提供的存储机制为事务消息提供了持久化能力;RocketMQ的高可用机制以及可靠消息设计则为事务消息在系统发生异常时依然能够保证达成事务的最终一致性。

执行流程如下 :

1、Producer(MQ发送方)发送事务消息至MQ Server,MQ Server将消息状态标记为Prepared(预览状态),此时这条消息消费者(MQ订阅方)是无法消费到的。

2、MQ Server接收到Producer发送给的消息则回应发送成功表示MQ已接收到消息。

3、Producer端执行业务代码逻辑,通过本地数据库事务控制。

4、若Producer本地事务执行成功则自动向MQ Server发送commit消息,MQ Server接收到commit消息后将“增加积分消息”状态标记为可消费,此时MQ订阅方(积分服务)即正常消费消息