第100篇文章啦!分布式事务在面试中分布式事务也是十分重要的点,所以学习完分布式锁后我们就来学习分布式事务吧。
事务表示的是我们在业务逻辑中对数据库进行操作的一组单元,需要同时成功或同时失败,不了解的小伙伴们可以看一下下面的文章。
Spring事务及工作中的使用
一般的事务可以在一个微服务中对于数据库的操作进行管理,但在多个微服务间调用时会失效,如下场景:
所以此时我们就需要用到分布式事务的解决方案。
分布式事务解决方案思路分析
我们可以对各个微服务调用的结果进行保存,当各个微服务应用业务流程执行后不提交事务,而是回到总的调用者中,由调用者对各个事务进行判断,所有服务的结果都正确时,才会给各个系统发送信息,各个系统进行事务提交。
这种思路就是2pc提交协议,2pc提交就是将整个事务提交过程分为两个阶段,由事务协调者进行判断,第一个阶段为执行业务逻辑,将业务逻辑的执行结果返回给事务协调者。第二个阶段为提交执行事务,如果各个服务的业务执行结果都为同意则提交事务,如果有一个服务执行结果失败了则回滚。
这种方式其实是有缺点的:
1.单点故障:事务协调者出错,会导致事务失败,会出问题,可以通过集群解决。
2.阻塞资源:因为各个服务执行业务逻辑的时长不同,在分布式事务中,事务协调者会等待所有服务响应后进行事务处理,也就是说所有服务都需要等待处理时间最长的服务调用结束,事务协调者给出结果之后才能继续向下执行提交或回滚,在之前微服务线程会一直被阻塞,数据库连接也会一直被占用。解决方案是第一阶段直接提交,对原数据进行备份,如果第二阶段是回滚,则根据备份的原数据进行还原,这是seata(阿里巴巴的分布式事务框架)对2pc提交协议的优化-AT模式。
3.数据不一致:当二阶段事务协调者发送提交信息的时候,此时某个微服务报错了,这时此服务的数据则丢失,不会被提交。解决方案可以通过人工介入,可以通过运维处理,也可以通过脚本进行数据对照进行更新或回退。
在2pc的基础上,又衍生除了3pc提交协议(理论性质,没人用),他在2pc提交协议的基础上加了一个前置检查阶段,通过校验判断业务逻辑是否合法合规,由此提高3pc提交协议中执行业务逻辑处理落表时的成功概率。
我们上面提到了阿里的分布式事务框架seata,其中他对2pc提交协议的优化具体原理是在一阶段执行业务逻辑时,通过解析SQL进行undolog日志储存,当二阶段需要回滚时,根据BranchId进行逆操作。
在seata框架中还有另一种模式,就是TCC模式(Try Confirm Cancel)这个模式的原理是将原本一阶段提交的业务逻辑分为两阶段提交,假设我们需要A转账给B 10元,原逻辑为A - 10 ,B + 10,这个业务逻辑分为两个阶段,第一个阶段(Try)为A余额-10,冻结金额+10;B冻结金额+10,第一阶段的处理一般为修改处理中状态,或冻结库存、金额等操作。如果此时Try操作成功,则二阶段(Confirm)进行A冻结金额-10;B余额+10,冻结金额-10。如果一阶段Try操作失败,则进行逆操作(Cancel)。
在TCC模式中我们要注意:
1.当Try时失败或异常,会直接调用Cancel进行回滚逆处理。
2.当多个服务的Confirm有某个服务失败了,那么所有服务的Confirm都会进行重试(要注意服务中Confirm业务逻辑的幂等性,多次调用时不该累加修改)。
3.若某个服务的Cancel失败了,那么所有服务的Cancel都会进行重试(要注意服务中Cancel业务逻辑的幂等性,多次调用时不该累加修改)。
4.当Try失败后,调用Cancel,很可能出现空回滚的情况(没有收到Try请求,但进行了Cancel),应当允许发生。
5.防止悬挂,当Try请求超时后,进行了Cancel空回滚情况,在处理之后收到了超时的Try请求,此时我们应该直接拒绝,因为对于单次分布式事务来说一次请求已经结束了,此时的Try请求没有意义。
到这里分布式事务的知识就差不多了,分布式事务主要强调的是数据的实时性,当用户调用接口时,我们需要立刻处理并将结果返回的时候需要用到此方法。如果实时性要求不高,我们就可以通过消息队列的方式进行处理,先对请求进行校验保存,确认数据无误后落表,等待服务器依次处理,保证处理结果的最终一致性。
希望对小伙伴们有所帮助。