dcddc

西米大人的博客

0%

系统学习分布式事务

归纳总结

通过这篇文章,你能了解到:

  • CAP 的含义
    • 一致性、可用性、分区容错性
  • 刚性分布式事务和柔性分布式事务的区别
    • CP 型和 AP 型
  • 分布式事务的实现原理:二阶段提交 2PC
    • 事务执行分为确认阶段和执行阶段。确认阶段进行逻辑校验和资源预留,执行阶段由事务管理器负责,不断重试保证分布式事务执行后的数据一致性
  • AP 型分布式事务的实际使用案例
    • TCC
      • TCC 是一种分布式事务的编程模型,它将分布式事务拆分为 try-confirm-cancel 三个步骤,try 和 confirm 负责执行事务,其中任何一步执行失败都会在 cancel 阶段执行回滚
    • rocketmq 的事务消息
      • 2PC 的确认阶段:prepare 半事务消息+本地事务+commit 消息+mqBroker 回调查询本地事务结果。2PC 的执行阶段:mqBroker 保证事务消息一定可被投递到消费端执行分布式事务。回滚阶段:本地事务执行失败,发 rollback 消息,删除 mqBroker 侧的 prepare 消息
    • 本地事务消息表
      • 把分布式事务的 mq 消息落库操作和本地事务做在一起。定时扫表发送分布式事务消息,成功后从本地事务消息表删除。不推荐,不如直接用 mq 的事务消息
    • 补偿型分布式事务
      • 适合于每个分布式事务一定可被执行。通过注解+aop 方式,对执行分布式事务的方法做增强,如果执行失败,写补偿表,定时扫补偿表重试该方法,需要每个分布式事务做幂等。但这种方式完全放弃了一致性

CAP 理论

分布式系统中,数据可能分布在多个缓存服务器、数据库中,且这些服务器、数据库往往都部署在多个网络分组中,所以可以说:分布式系统中,数据是多网络环境多物理空间存储的

多网络分组、多物理空间存储的数据,核心问题就是要解决数据读取一致性。因此,就有了 CAP 理论来描述这种问题

CAP 即 Consistency、Avaliability、PartitionTolerence,一般分布式系统只能保证CP或AP,无法同时满足CAP

Consistency 即一致性,需要保证任何时刻分布式系统中数据存储的结果是一致的。因此数据写入时,需要对写入的所有分布式空间加读写锁,这期间数据是无法被外部访问的,因此不满足 Avaliability,即可用性。所以分布式系统中一致性和可用性是相互矛盾的,无法同时满足

PartitionTolerence 即分区容错性。分布式系统中服务器、数据库会部署在多个网络分组中(分区的含义),相互间通信需要网络调用,因此超时、丢包问题无法避免,因此需要容忍网络超时或丢包问题(容错的含义)。所以分布式系统必须具备 P,分区容错性,可以通过回滚或重试来保证分区容错性

分布式事务的实现方案

CAP 理论在分布式系统的实际应用体现在分布式事务中。满足 CP 的分布式事务称为刚性分布式事务,对数据一致性是刚需的。反之是柔性分布式事务,对数据一致性不是刚需,只要保证最终一致性即可,但要保证可用性,即满足 AP

二阶段提交

无论是 CP 型还是 AP 型分布式事务,二阶段提交(2PC,2 phase commit)都是一个常用的理论方案。二阶段提交将事务的执行拆分为两个阶段,即确认阶段和执行阶段。确认阶段由业务验证事务执行的合法性,并预留资源。执行阶段往往由事务管理器负责,保证分布式事务一定被全部执行

只有在确认阶段所有事务执行者都确认并预留资源成功,才会在执行阶段真正执行分布式事务,否则回滚预留资源,分布式事务执行失败

CP 型分布式事务的实现方案

CP 型分布式事务的执行效果和执行本地事务是一致的,要么都成功,要么全部回滚,且事务执行期间,外部无法访问数据。即 CP 型分布式事务满足事务的 ACID 特性,原子性、一致性、隔离性、持久化。

二阶段提交-XA 协议

实现 CP 型分布式事务的典型代表是 XA 协议,它将分布式系统划分为:业务应用、资源管理器、事务管理器。由事务管理器承接业务应用的分布式事务请求,面向资源管理器(各类商业数据库)统一执行分布式事务

XA 协议基于二阶段提交,由事务管理器先向所有实现了XA接口的资源管理器发起投票,称为 prepare 阶段。如果 prepare 阶段有投票反对,由事务管理器对所有资源管理器发起回滚。如果投票全部通过,执行分布式事务,称为 commit 阶段。这个过程中如果资源管理器宕机或网络请求异常,由事务管理器进行重试补偿

资源在 prepare 阶段就已经被锁定,直到回滚或所有数据 commit 成功后才释放,需要长时间锁定资源的读写,因此不适合长事务,不满足高并发场景,实际应用中使用较少

AP 型分布式事务的实现方案

AP 型分布式事务保证数据最终一致性,不会锁定资源的读写操作,过程中可能出现短暂的数据不一致,但适合高并发场景。
最终一致性在互联网应用场景中被广泛用做吞吐量和ACID的妥协点

TCC 编程模式

所谓的 TCC 编程模式,是二阶段提交的一个变种。TCC 提供了一个编程框架,将整个业务逻辑分为三块:Try、Confirm 和 Cancel 三个操作。以在线下单为例,Try 阶段会去扣库存,Confirm 阶段则是去更新订单状态,如果更新订单失败,则进入 Cancel 阶段,会去恢复库存。总之,TCC 就是通过代码人为实现了两阶段提交,不同的业务场景所写的代码都不一样,复杂度也不一样,因此,这种模式并不能很好地被复用。

事务消息

阿里云 RocketMQ 的事务消息能实现分布式事务的最终一致性,是一种 AP 型分布式事务的解决方案。它核心思想还是借鉴了二阶段提交

mq 的 broker 扮演事务管理器的角色,broker 需要得到业务方(消息生产者)真正的确认回执,然后由 broker 保证消息一定能投递到消费端完成分布式事务中后续的事务执行操作,达到事务最终一致性。具体的执行过程描述如下

二阶段提交的确认阶段:

  • 业务应用首先发送 prepare 消息(半事务消息)到 MQ
  • 在发送 prepare 消息成功后执行本地事务
  • 根据本地事务执行结果返回 commit 或者是 rollback
    • commit 后的消息称为事务消息
    • 如果消息是 rollback,MQ 将删除该 prepare 消息不进行下发
  • 如果 broker 长时间拿不到半事务消息的结果(例如业务应用挂了或网络超时),broker 会主动调业务应用查询事务状态
    • 需要业务应用实现回调接口

二阶段提交的执行阶段:

  • mq 保证事务消息一定能被消费端成功消费
    • 投递失败会重试,因此消费方需要保证分布式事务幂等执行

你可能会问,我何不把发 mq 消息也放到本地事务里,一旦发 mq 消息失败,本地事务就回滚,不也能实现分布式事务么?实际上这是有问题的,事务消息能保证本地事务和消息投递的强一致性,只要本地事务执行成功,一定能由 mq 服务端保证分布式事务执行成功。但如果把发 mq 放到本地事务,可能本地事务成功了,mq 发送失败,但这却要回滚本地事务,对资源是一种浪费。

本地事务消息表

本地事务消息表的实现方案:

  • 创建本地事务消息表
  • 执行本地事务和消息数据写入本地事务表放在一个事务里,保证本地事务执行和消息投递的强一致性
  • 定时任务从消息表中获取消息数据
  • 发送消息
  • 删除本地消息

该方案也是 AP 事务的一种实现,和事务消息相比,引入定时器且需要额外的存储资源,也仍然需要依赖分布式消息队列如 rocketMq,复杂度和资源开销都更高,不推荐

补偿型分布式事务

补偿型分布式事务适用于一定可以执行分布式事务的业务,解决一些分布式事务执行过程中因网络抖动、丢包造成的失败场景

一连串分布式事务操作同步调用时,极易发生接口整体超时情况,因此特别适合于补偿型分布式事务

实现上可以通过 TOC 方式:

  • 定义一个补偿表,保存分布式事务执行方法的 bean 名称,方法签名,方法参数
  • 定义一个补偿注解,加在分布式事务方法上
  • 通过 aop 将带上注解的方法作为切面方法做增强,如果分布式事务方法执行失败或异常,写入补偿表
  • 通过定时任务扫表补偿。当然,需要保证分布式事务执行的每一个方法都幂等,否则不能补偿

这种补偿型分布式事务,通过 aop+注解的方式减少对业务侵入,但它完全放弃了一致性,且不支持回滚

参考资料

https://blog.csdn.net/m0_38110132/article/details/77043580
https://blog.csdn.net/m0_38110132/article/details/76994165