Jta分布式事务实现原理

181 阅读5分钟

前言

Jta是Java中专门定义的JSR 907 Java Transaction API,基于XA模式在Java语言中的实现了全局事务处理的标准。

什么是XA(eXtended Architecture)

1991 年,为了解决分布式事务的一致性问题,X/Open组织(是一个欧洲基金会,该组织的目标是促进对UNIX语言、接口、网络和应用的开放式系统协议的制定)提出了一套名为X/Open XA 的处理事务架构,其核心内容是全局的事务管理器(Transaction Manager)和局部的资源管理器(Resource Manager)之间的通信接口。XA接口是双向的,在事务管理器和多个资源管理器之间形成通信桥梁,通过协调多个数据源的一致动作,实现全局事务的统一提交或者统一回滚。

分布式为什么会导致不一致

如果访问的是单一数据库,所有的操作都在一个库中,事务由数据库保证;当访问的是多个数据库时,因为属于不同的事务提交,无法保证一致性。

例如:去超市买瓶水,当支付时进行的操作为:扣除消费者的钱,超市获得钱,商品数量减少,当 消费者,超市和商品都属于不同的数据库时
public void buy() {
    //伪代码
    消费者.begin();
    超市.begin();
    仓库.begin();
	try {
        消费者花钱;
        超市收到钱;
        仓库的库存减少;
        //当消费者、超市的事务提交成功,仓库事务提交失败,进入异常也不会回滚,导致数据不一致
        消费者.commit();
        超市.commit();
        仓库.commit();
	} catch(Exception e) {
        消费者.rollback();
        超市.rollback();
        仓库.rollback();
	}
}

如何保证分布式事务一致性

二段法

  • 准备阶段:又叫作投票阶段,在这一阶段,先确定协调者,一般是从参与者中选出的,协调者询问事务的所有参与者是否准备好提交,参与者如果已经准备好提交则回复Prepared,否则回复Non-Prepared。对于数据库来说,是在重做日志(redo)中记录全部事务提交操作所要做的内容,但暂不写入最后一条Commit Record,但仍继续持有锁。

  • 提交阶段:又叫作执行阶段,协调者如果在上一阶段收到所有事务参与者回复的 Prepared 消息,则先自己在本地持久化事务状态为Commit,在此操作完成后向所有参与者发送 Commit 指令,所有参与者立即执行提交操作;否则,任意一个参与者回复了 Non-Prepared 消息,或任意一个参与者超时未回复,协调者将自己的事务状态持久化为Abort之后,向所有参与者发送 Abort 指令,参与者立即执行回滚操作。对于数据库来说,这个阶段的提交操作应是很轻量的,仅仅是持久化一条 Commit Record 而已,通常能够快速完成,只有收到 Abort 指令时,才需要根据回滚日志(undo)清理已提交的数据。

缺点

  • 单点问题:协调者一旦宕机,所有参与者都会受到影响。如果一直没有恢复(没有正常发送 Commit 或者 Rollback 的指令),那所有参与者都必须一直等待。
  • 性能问题:两段提交过程中,所有参与者相当于被绑定成为一个统一调度的整体,期间要经过两次远程服务调用(准备阶段协调者询问参与者,提交阶段协调者通知参与者),三次数据持久化(准备阶段写重做日志,协调者做状态持久化,提交阶段在日志写入 Commit Record),整个过程将持续到参与者集群中最慢的那一个处理操作结束为止,这决定了两段式提交的性能通常都较差。
  • 一致性风险:前面已经提到,两段式提交的成立是有前提条件的,当网络稳定性和宕机恢复能力的假设不成立时,仍可能出现一致性问题。尽管提交阶段时间很短,但这仍是一段明确存在的危险期,如果协调者在发出准备指令后,根据收到各个参与者发回的信息确定事务状态是可以提交的,协调者会先持久化事务状态,并提交自己的事务,如果这时候网络忽然被断开,无法再通过网络向所有参与者发出 Commit 指令的话,就会导致部分数据(协调者的)已提交,但部分数据(参与者的)既未提交,也没有办法回滚,产生了数据不一致的问题。

三段法

在二段法的基础上,将准备阶段分为:询问阶段和预处理阶段。

  • 询问阶段(canCommit):协调者让每个参与者根据自身状态,评估该事务是否有可能顺利完成。
  • 预处理阶段(preCommit):同二段法的准备阶段。
  • 提交阶段(doCommit):同二段法的提交阶段,不同点在于:增加了询问阶段,成功提交概率增大,当协调者crash时,默认是提交事务而不是回滚事务或者持续等待。