分布式事务框架 tcc-transaction
背景
场景1: 企业版需一周内需要上线一个需求。需要 服务端,前端,测试参与。 服务端开发两天完成,前端开发两天完成,但是测试这周排期满了,没有时间测试,那这个需求上线不了。
场景2: 小明需要将A银行卡里的钱,转到B银行。A银行系统扣款成功,B银行入账失败。
场景3: 小王喜欢小唐,但是小唐父母觉得女儿需要个房子住。他们先结婚,几年后再买房。最终小两口还是有房子住
概念
什么是事务
事务(Transaction),一般是指要做的或所做的事情, 通俗讲一般是指一系列操作,要么都成功,要么都不成功,通过确保系统中的独立操作全部成功完成或全部成功取消来维持系统的完整性。
Java实现事务的几种方式:jdbc事务,jta事务,容器事务
本地事务
本地事务一般是指依靠关系型数据库本身的事务特性来实现本地事务。
数据库事务的四大特性 ACID:
A(Atomic) : 原子性,构成事务的所有操作,要么都执行完成,要么全部不执行
C(Consistency):一致性,在事务执行前后,数据库的一致性约束没有被破坏。
I(Isolation): 隔离性,数据库中的事务一般都是并发的,隔离性是指并发的两个事务的执行互不干扰。可设置不同数据库事务隔离级别。(RU, RC, RR, Serializable)
D (Durability):持久性,事务完成之后,该事务对数据的更改会被持久化到数据库,且不会被回滚。
本地事务程序实现
基本流程流程: begin, commit, rollback 操作。
begin transaction;
try {
write db;
commit transaction;
} catch(Exception e ){
rollback transaction;
}
本地事务基本是依靠数据库事务实现。在java中,本地事务基本基于jdbc事务实现,通过Connection 对象控制
public void setAutoCommit(boolean)
public void commit()
public void rollback()
spring 程序中可在方法上添加 @Transactional 注解,或自己通过AOP实现
利: 实现简单。开发少。强一致
局限:局限于单个数据库链接
分布式事务
在分布式系统下。会有多数据库实例,多服务。会产生 跨jvm,同一个数据库;同一个jvm,跨数据库; 跨jvm,跨数据库 三种情况的分布式事务。
理论基础:
分布式系统需要满足 CAP 定理,即:
一致性(consistency):
可用性(avaliable);
分区容忍性(Partition tolerance);
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)这三项中的两项。即在分布式系统中,满足P的前提下,C和A只能满足其中一个。根据实际业务场景选择。
1) AP:
放弃一致性,追求分区容忍性和可用性。这是很多分布式系统设计时的选择。
接受所查询到的数据在一定的时间内不是最新的数据。如消息异步处理同步;通过查询来确认最终处理结果
2)CP:
放弃可用性,追求强一致性和分区容错性。不是系统不可用,只是性能不佳
如 zookeeper选举; 跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完成。
3)AC:
放弃分区容忍性。不分区,不部署子节点。可不考虑网络,或其他节点挂掉的问题,实现强一致性或可用性。但不符合现有多数分布式系统设计原则。
多数业务场景,追求性能体验。允许暂时的数据不一致。即AP系统设计
BASE 理论
BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。BASE理论是对CAP中AP的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足BASE理论的事务,我们称之为“柔性事务”。
常见分布式事务实现方式:
1、两段提交 (2PC)
2PC即两阶段提交协议,是将整个事务流程分为两个阶段,准备阶段(Prepare phase)、提交阶段(commit phase),2是指两个阶段,P是指准备阶段,C是指提交阶段。
基本流程:
XA 规范
X/Open DTP 模型:
包括应用程序( AP ):
事务管理器( TM ): transaction-manager
资源管理器( RM ):DB
通信资源管理器( CRM ):网络通信 (可忽略)
基于TM和RM之间通讯的接口规范为XA规范,可通过数据库的XA协议实现2PC方案。
实现
通过JTA(java transaction api)实现。
在java程序中,如果不使用 JBOSS, WEBLOGIC等容器。可通过 jotm, atomikos等方案实现。
也可通过 seata 框架实现。
利: 强一致性,开发量小,业务不侵入
局限:资源锁定时间长,不适用于高并发场景。 依赖资源层(RM)。
存在的问题:
同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态
单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
数据不一致。在二阶段提交的阶段二中,只有部分commit
由上述问题,引入三阶段提交
2、tcc (try、confirm、cancel)
补偿型事务
原理:
各步骤职责:
try阶段:
1)业务检查
2)预留本次业务所需资源
confirm 阶段(try正常执行无异常):
1)执行业务
2)不做业务检查
3)只使用try阶段所预留的资源
4)confirm接口满足幂等(会重试)
cancel 阶段(try执行发生异常时):
1)释放try阶段预留的资源
2)cancel操作满足幂等(重试)
注意事项:
1、空回滚:在没有调用try方法的情况下,调用了cancel。cancel需要识别空回滚,直接返回成功。(如:由于网络异常或子业务宕机等情况,子业务的try方法没有执行或者没有进行资源锁定。在网络或服务恢复之后,会调用cancel方法)
2、执行顺序:在try方法超时的情况下,直接调用cancel方法。会导致cancel逻辑先执行完成,而try方法再进行资源锁定。这种情况下锁定的资源将不能释放。 需要延迟cancel。
3、confirm和cancel保证幂等:因为会失败重试。如果未保证幂等,则会重复使用或者重复释放资源。会导致数据不一致。
利:tcc属于补偿型事务,由多个分支事务组成,分支逻辑执行之后会提交本地事务,不会长时间锁定数据库资源。由业务逻辑实现提交,补偿逻辑。更加灵活
局限:提交,补偿逻辑由业务代码实现,开发量大。有一定的业务侵入。最终一致
2、
框架1: tcc-transaction
github:https://github.com/changmingxie/tcc-transaction