分布式事务的由来,当两个系统一个负责扣款 ,一个负责发货,但是扣款的系统出现异常,扣款失败,货还在正常发送,这时候分布式事务就出现了。
简单来说,就是一次大的操作都由小的操作来组成,这些小的操作部署在不同服务器上,且属于不同的应用,分布式事务保证这些操作要么全部成功,要么全部失败。
首先理解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阶段:
比如商品系统用户点击购买商品,
订单数据库这时候改为‘下单中’。
账户金额数据库金额扣减,冻结资金10,剩余90.
库存系统数据库 库存扣减,冻结1.
Confirm阶段:
订单数据库这时候改为‘下单成功’。
账户金额冻结金额扣减成功,剩余90.
库存数据库扣减成功。
Cancel阶段:
订单数据库更新为‘下单失败’。
金额还原成100,状态支付失败。
库存还原成100,下单失败。
TCC方案适合强一致性,适合金钱相关的,因此需要大量业务处理补偿代码,提供补偿机制。有开源的TCC框架,TCC-transaction。
本地消息表
A系统首先写入业务表,然后写入消息表,将消息通过mq发送给B系统。
B系统首先写入消息表,可以通过主键唯一性保证不会重复消费,之后再写入业务表,当业务执行成功,再发送消息到mq。
A系统这时候就会监听到B系统是否成功,再根据B系统的mq消息来决定是否回滚。
最大努力通知方案
使用于一些最终一致性低的业务,入银行和商户通知等。
A系统在本地事务完成之后,通过mq不断通知b系统去发送消息给用户,如果ok则成功,不ok则重试几次进入死信队列或者补偿机制。