分布式事务如何解决?

2022-12-14 18:27:51 浏览数 (1)

分布式事务的由来,当两个系统一个负责扣款 ,一个负责发货,但是扣款的系统出现异常,扣款失败,货还在正常发送,这时候分布式事务就出现了。

简单来说,就是一次大的操作都由小的操作来组成,这些小的操作部署在不同服务器上,且属于不同的应用,分布式事务保证这些操作要么全部成功,要么全部失败。

首先理解cap定律:可用性,一致性,分区容错率。因为三者不可以同时满足,于是就出现了base理论,base意思是保证分区容错率和可用性,来用最终一致性来解决一致性问题。

当我们A系统数据修改成功,传递给B系统的时候,出现异常,这时候B系统还是之前的数据,于是就导致了一致性失效,只保证了可用性和分区容错率。

那么我们这时候如何保证一致性呢,就需要牺牲分区容错率,当发生异常的时候进行事务的回滚,这种业务场景在数据库需要保证高一致性的情况下使用很多,双11这种场景就会牺牲分区容错率保证数据一致性。

分布式解决方案?

一、2PC两阶段提交方案/XA方案

一个系统担任协调器角色,其他系统担任参与者,主要分为conmmit-request阶段和commit。

请求阶段:协调者向所有参与者发起准备提交请求,然后收集。

提交阶段:如果全都是ok,则会提交请求,否则进行回滚或者取消提交请求。

方案缺陷:

同步阻塞:所有参与者都是事务同步阻塞,当参与者占有公共资源,其他访问节点访问时候则不得不阻塞。

无法高可用:单点故障,一旦协调者出问题,系统则不可用。

数据不一致:当参与者有的没接收到消息,处于阻塞,这段时间则不一致。

不确定性:当协调者发送commit,这时候只有一个参与者受到新消息,当参与者与协调者宕机时候,新选举的协调者无法判断是否已提交消息。

XA解决方案可以用springBoot atomikos jta来实现分布式事务处理。

3pc对于协调者和参与者都设置了超时时间,而2pc只有协调者才有超时机制。避免了参与者长时间未收到commit消息,无法释放资源问题,参与者长时间未收到commit会自动进行本地commit进而释放资源。另外canCommit、preCommit、doCommit是哪个阶段的设计,保证了参与节点各个状态一致。

二、TCC方案

Tcc方案分为try confirm cancel三个阶段。

Try(尝试待执行的任务):并没有真实执行,检查所有业务需要的资源,并预留。

Confirm(执行业务):直接执行业务,因为之前有预留资源,直接使用。

Cancel(回滚):业务执行失败,则会释放所有资源,并回滚已操作数据。

try阶段:

比如商品系统用户点击购买商品,

1、订单数据库这时候改为‘下单中’。

2、账户金额数据库金额扣减,冻结资金10,剩余90.

3、库存系统数据库 库存扣减,冻结1.

Confirm阶段:

1、订单数据库这时候改为‘下单成功’。

2、账户金额冻结金额扣减成功,剩余90.

3、库存数据库扣减成功。

Cancel阶段:

1、订单数据库更新为‘下单失败’。

2、金额还原成100,状态支付失败。

3、库存还原成100,下单失败。

TCC方案适合强一致性,适合金钱相关的,因此需要大量业务处理补偿代码,提供补偿机制。有开源的TCC框架,TCC-transaction。

三、本地消息表

1、A系统首先写入业务表,然后写入消息表,将消息通过mq发送给B系统。

2、B系统首先写入消息表,可以通过主键唯一性保证不会重复消费,之后再写入业务表,当业务执行成功,再发送消息到mq。

3、A系统这时候就会监听到B系统是否成功,再根据B系统的mq消息来决定是否回滚。

四、最大努力通知方案

使用于一些最终一致性低的业务,入银行和商户通知等。

A系统在本地事务完成之后,通过mq不断通知b系统去发送消息给用户,如果ok则成功,不ok则重试几次进入死信队列或者补偿机制。

0 人点赞