目录
前言:
最近在做支付相关的开发,因为业务涉及到与钱相关的代码,所以使用到了分布式事务。在这里做一下总结。
这是要感谢一下尼恩的博客!他写得非常详细,借鉴一下他的一张图。
什么是分布式事务?
对于分布式系统而言,需要保证分布式系统中的数据一致性,保证数据在子系统中始终保持一致,避免业务出现问题。分布式系统中对数要么一起成功,要么一起失败,必须是一个整体性的事务。
分布式事务指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
简单的说,在分布式系统上一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务节点上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。
举个例子:在电商网站中,用户对商品进行下单,需要在订单表中创建一条订单数据,同时需要在库存表中修改当前商品的剩余库存数量,两步操作一个添加,一个修改,我们一定要保证这两步操作一定同时操作成功或失败,否则业务就会出现问题。
任何事务机制在实现时,都应该考虑事务的ACID特性,包括:本地事务、分布式事务。对于分布式事务而言,即使不能都很好的满足,也要考虑支持到什么程度。
为什么要使用分布式事务?
如果我们的服务只使用单一的数据库,那么我们可以使用本地事务就可以解决在业务流程中数据的一致性问题。
但是当我们服务是分布式的数据库也是多个的时候,我们的本地事务就无法保证业务流程中数据的一致性问题了。但是我们的许多业务场景中必须要我们的数据保持一致性,所以我们就不得不引入分布式事务来解决这个数据不一致的问题。
分布式事务只是一个理论。现在开源的分布式事务框架也有许多。有的公司有自研的分布式框架。当然也有开源的分布式框架我们可以直接使用。
分布式事务怎么用?
1.首先我们知道我们要选择分布式事务来解决我们分布式系统的数据一致性问题。但是分布式事务为了更加的适应或者说适合我们的业务场景。出现了一个CAP定理,它大致就是说我们必须在强一致性和可用性中选择一个。
举一个简单的例子:
问:为什么分布式系统中无法同时保证强一致性和可用性?
答:首先一个前提,对于分布式系统而言,分区容错性是一个最基本的要求,因此基本上我们在设计分布式系统的时候只能从一致性(C)和可用性(A)之间进行取舍。
如果保证了一致性(C):对于节点N1和N2,当往N1里写数据时,N2上的操作必须被暂停,只有当N1同步数据到N2时才能对N2进行读写请求,在N2被暂停操作期间客户端提交的请求会收到失败或超时。显然,这与可用性是相悖的。
如果保证了可用性(A):那就不能暂停N2的读写操作,但同时N1在写数据的话,这就违背了一致性的要求。
这里说的一致性是指强一致性。
2.根据我们的业务场景,如果我们必须要强一致性那么我们就选择强一致性的分布式事务框架,在这里推荐可以使用阿里开源的seate-AT框架。
强一致性的框架有一个前提:基于支持本地 ACID 事务的关系型数据库,Java 应用,通过 JDBC 访问数据库。因为强一致性的分布式事务框架底层是使用的是本地事务的ACID来保证的。
我们上图中CP下面的全都是强一致性的分布式事务。
3.我们有一些业务场景对可用性的要求更高或者我们的数据库不支持ACID,或者我们根本就没有使用数据库,那么这个时候我们就只能选择另外一种方案,对一致性的要求我们允许不是实时性的一致性。我们允许隔一段时间,达到我们最终希望的一致性即可。
我们上图中AP上的全都是分布式事务最终一致性的方案,推荐可以使用阿里开源的seate-tcc。
4.重点讲解一下最终一致性的分布式事务补偿型TCC
TCC 分布式事务模型包括三部分
Try 阶段: 调用 Try 接口,尝试执行业务,完成所有业务检查,预留业务资源。
Confirm 或 Cancel 阶段: 两者是互斥的,只能进入其中一个,并且都满足幂等性,允许失败重试。
Confirm 操作: 对业务系统做确认提交,确认执行业务操作,不做其他业务检查,只使用 Try 阶段预留的业务资源。
Cancel 操作: 在业务执行错误,需要回滚的状态下执行业务取消,释放预留资源。
Try 阶段失败可以 Cancel,如果 Confirm 和 Cancel 阶段失败了怎么办?
TCC 中会添加事务日志,如果 Confirm 或者 Cancel 阶段出错,则会进行重试,所以这两个阶段需要支持幂等;如果重试失败,则需要人工介入进行恢复和处理等。
5.TCC 的使用场景
TCC是可以解决部分场景下的分布式事务的,但是,它的一个问题在于,需要每个参与者都分别实现Try,Confirm和Cancel接口及逻辑,这对于业务的侵入性是巨大的。
TCC 方案严重依赖回滚和补偿代码,最终的结果是:回滚代码逻辑复杂(如果我们的数据源是支持ACID的那么我们可以使用seate-tcc,业务seate-tcc的TCC模式还支持与AT模式混合使用。这个时候我们就可以不用写回滚代码,直接使用本地事务就可以回滚),业务代码很难维护。所以,TCC 方案的使用场景较少,但是也有使用的场景。
比如说跟钱打交道的,支付、交易相关的场景,大家会用 TCC方案,严格保证分布式事务要么全部成功,要么全部自动回滚,严格保证资金的正确性,保证在资金上不会出现问题。
6.seate-tcc和seate-AT的使用介绍。
可以参考seate官网里面有详细的集成教程 https://seata.io/zh-cn/blog/integrate-seata-tcc-mode-with-spring-cloud.html
参考资料