分布式事务的四种方式方案的优缺点

目录

    • 2pc 两阶段提交方案
      • 第一阶段: 准备阶段
      • 第二阶段 : 提交阶段
      • 2PC的优劣
        • 优点:
        • 缺点:
    • 3PC三阶段提交的问题
      • 第一阶段: 准备阶段
      • 第二阶段: 预提交阶段
      • 第三阶段: 提交阶段
      • 3PC的优劣
    • TCC事务提交机制
      • 第一阶段: 准备事务冻结资源阶段
      • 第二阶段 成功消费资源 / 失败解冻资源 阶段
      • TCC的优缺点
    • 使用事务MQ来保证分布式事务
      • 支持事务的MQ
      • 最终一致性解决事务
      • MQ消息的优劣
    • 总结:

现在最流行的就是分布式应用, 而分布式应用就要面临分布式事务的问题。现在主流的已经有四种分布式事务的解决方案。 这篇文章就是我自己的关于分布式事务的理解。

文章内容只是我自己的理解, 如果有不正确的地方欢迎各位指正。

2pc 两阶段提交方案

两阶段提交需要把事务分成两步来处理, 同时还需要一个事务管理器来协调分布式事务。

第一阶段: 准备阶段

分布式事务的四种方式方案的优缺点_第1张图片

第一阶段 事务管理器先发送事务指令到两个应用, 让两个应用开始事务,这时两个应用就会开始锁定资源, 准备事务,准备好后就通知到事务管理器。

第二阶段 : 提交阶段

事务管理器收到第一阶段的通知后,就会根据第一阶段的结果来发布第二阶段的指令

  1. 如果第一阶段有应用A准备事务失败, 事务管理器此时发布的第二阶段的指令就是让应用B取消事务。
  2. 如果第一阶段都成功了后, 事务管理器此时就会发布事务提交指令到两个应用,让他们提交事务

2PC的优劣

优点:

两阶段提交是强事务性, 如果是正常流程能够保证事务一致性

缺点:

1.阻塞等待性能不高, 因为强事务性, 每个应用都会阻塞等待其他事务的完成, 这个阻塞就会导致效率不够。 这个很类似BIO。

  1. 单点故障问题, 如果在第一阶段完成了后, 事务管理器挂掉了后, 此时两个应用会一直阻塞等待, 事务无法完成

  2. 还是会出现事务不一致性, 如果事务管理器发送第二阶段提交是的指令,如果这个时候应用A没有收到指令(网络波动)。此时B提交了事务,A没有提交,就会导致事务不一致。

3PC三阶段提交的问题

三阶段提交 是在两阶段提交的基础上进行的改进, 主要为了解决两阶段的部分缺点问题。3pc设置了超时时间的机制, 并且增加了一个阶段。

第一阶段: 准备阶段

事务管理器发送准备指令到两个应用A和B, 让A和B准备事务,A和B准备好了会通知事务处理器,此流程和2pc的第一阶段的流程一样。

第二阶段: 预提交阶段

这个是和2PC不一样的阶段, 此时如果事务管理器收到了第一阶段准备好了指令后,就会发布第二阶段的指令,让事务A和B进行预提交操作。

预提交就是A和B收到指令开始提交事务, 并记录好事务的日志,但是不释放锁资源等,然后再返回通知给事务管理器告知预提交完成。

第三阶段: 提交阶段

事务管理器收到第二阶段的指令后, 如果此时有事务预提交失败, 就会通知应用A和B取消事务, 事务开始失败。

如果第二阶段预提交全部成功后,事务管理器就会发布第三阶段指令, 提交指令。 应用A和B收到指令后就会释放锁, 事务完成。

3PC的优劣

优点:

  1. 设置了超时时间, 一定性的解决单点故障问题。
  • 如果在第二阶段只是收到第一阶段的指令后,事务管理器挂了, 这个事务应用A和B阻塞一定的时间后, 发现还是连接不上事务管理器就会释放锁。
  • 如果 预提交指令发送了后,事务管理器挂了, 这个时候应用A和B无法接受到提交指令, A和B阻塞到一定时间后, 就会自己提交事务, 因为如果预提交指令都收到了, 说明所有的应用都已经准备好了应用,这个时候提交事务问题是不大的。

缺点:

  1. 性能问题, 在三个阶段的中间还是会有事务阻塞的问题, 阻塞就会导致性能的低下。
  2. 如果因为网络抖动,导致预提交指令只有部分应用收到, 这个时候事务协调器挂了, 因为有超时提交的机制, 就会出现事务不一致的问题。

TCC事务提交机制

前面两个方案都是需要阻塞等待事务的提交, 性能不高,但是TCC提供了另外的一个思路, 就是想冻结事务需要的资源,再协调所有的应用的事务,如果所有应用都成功了就会提交事务,正常消费冻结资源, 如果有应用事务失败, 就会解冻所有冻结的资源, TCC也是需要分段的,同时也有一个事务管理器, 具体流程如下:

第一阶段: 准备事务冻结资源阶段

事务管理器发送指令到应用A和B , A和B此时就会把事务需要的资源先冻结资源, 冻结成功后就会返回通知给事务处理器。

事务失败的原因一般都是资源不够的情况, 比如扣减库存发现库存不足, 扣减金额发现金额不足等。 如果资源都冻结成功了,说明事务会成功的。

第二阶段 成功消费资源 / 失败解冻资源 阶段

事务管理器收到第一阶段的冻结成功指令后, 此时就会发送第二阶段执: 行事务消费资源的指令。 这个时候A和B应用就会使用冻结的资源执行事务。

如果 第一阶段某个应用冻结失败后, 此时事务管理器发送 解冻资源事务失败的指令。 这个时候应用A和B就会解冻资源, 事务失败

TCC的优缺点

优点:

不会阻塞其他的事务, 因为提前冻结了资源, 其他的事务就不会和他竞争资源了,自然就不会阻塞。 性能自然提高了。 性能提高就是最大的优势。

出现事务不一致的可能性低, 因为只是冻结资源, 如果此时出现问题事务协调器挂了, 此时数据还是一致性的(不会出现对不上帐的情况)。

缺点:

  1. 虽然冻结了资源不用和其他事务竞争增加了并发性,但是在本事务内部各个应用还是需要阻塞等待其他所有应用的完成的。

  2. 增加了业务的复杂度,需要程序员写大量的业务代码。

  • 冻结资源需要程序员写冻结资源的代码,
  • 解冻资源需要程序员写解冻资源的代码。
  • 消费资源需要程序员写消费资源的代码
  1. 对应用的侵入性强, 不同的业务需要使用不同的 冻结解冻消费资源业务代码。 并且各个应用不能通用。

  2. 事务失败的原因有多种,此时解冻资源的操作也会复杂

    比如网络波动没有收到指令, 此时可以重试解决。
    比如资源不足, 此时可以释放资源,事务失败。

使用事务MQ来保证分布式事务

上面的三种事务都是为了保证分布式系统中的事务的强一致性的, 但是我们换个思路, 允许事务短时间内不一致,只要事务最终是一致性的就可以了。

而使用支持事务的MQ来实现这个思想就十分方便了, 这里推荐阿里的RocketMQ来实现。

支持事务的MQ

RocketMQ现在支持了事务MQ了, 所谓的事务MQ就是指发送消息需要支持提交和回滚,如同数据库事务一样。

分布式事务的四种方式方案的优缺点_第2张图片

  1. 发送消息需要两步, 预发送和确认发送。 这里就可以和数据库事务相对应了,数据库事务开始, 这时候可以预发送消息,
  2. 如果数据库事务失败, 这个时候可以通知RocketMQ取消发送。 如果数据库事务成功, 可以确认发送
  3. 如果预发送后,应用挂了, RocketMQ会阻塞一段时间后会回调询问消息是否需要发送, 通过这个机制就可以防止MQ一致阻塞在RocketMQ
  4. 事务消息的投递会一直重试, 直到成功为止。 并且RocketMQ支持完善的监控,如果消息投递一直不成功会发出告警。

最终一致性解决事务

RocketMQ的投递确认和一直重试的特性 可以用来保证事务的最终一致性, 使用它来实现事务,十分方便, 并且各个应用完全不要阻塞,性能高效。但是会出现短暂的事务不一致。

最终一致性流程示意图大致如下:
分布式事务的四种方式方案的优缺点_第3张图片

  1. 订单系统发起事务消息,给库存系统和支付系统。 因为发送MQ需要两步, 事务发送出去了就说明订单系统的下订单操作一定是成功的。
  2. 库存系统收到消息后就会扣减库存, 它完全不用管用户的余额够不够, 因为这是支付系统关心的事情
  3. 支付系统受到消息后, 就会进行自己的操作, 也不会关系库存系统。
  4. 如果支付系统金额不足, 它会发送MQ到订单系统,这个时候订单系统就会执行退单操作, 会, 会发送回滚消息到库存系统, 库存系统就会执行回滚操作。

MQ消息的优劣

优点:

  • 同一个事务中各个应用不用阻塞等待其他的应用完成准备动作, 提高性能。 提高性能就是最大的优点。

缺点:

  • 需要写复杂的回滚代码,业务侵入性只比TCC好一点
  • 事务的一致性完全依赖于MQ服务
  • 短时间会有不一致的情况, 就是可能钱扣了,库存没有扣减。
  • 如果出现未考虑到的事务失败的情况,MQ消息会重复投递, 这个时候就需要运维监控MQ消息来发现了。

这个方案是完全的依赖MQ消息服务的, 而RocketMQ是独立的系统,完全可以使用各种方法来保证自己的高可用性。

总结:

完事有利就有弊, 分布式事务的四种方案都有自己的优缺点.

2PC和3PC 都是强一致性,就是使用事务协调器把单应用的事务协调到一起来完成的方案。这个方案会系统分布式的性能来确定事务的一致性,但是不用考虑回滚的复杂情况, 完全使用数据库的回滚操作。

TCC也是强一致性的, 它是换个思路的方式实现事务,他会先冻结资源, 这样就不用与其他的事务竞争公共资源,防止阻塞其他的事务,从而提高系统性能。但是它牺牲事务回滚操作的方便性和增加了冻结资源的操作

MQ消息事务 是最终一致性的, 事务类不用阻塞等待各个应用的完成,极高的提高性能。 但是它完全依赖MQ消息系统的高可用性,并且还要写复杂的回滚业务。

你可能感兴趣的:(java,分布式,事务)