原创

分布式事务相关研究

什么是分布式事务

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

分布式事务的重要性和挑战

微服务的发展

微服务倡导将复杂的单体应用拆分为若干个功能简单、松耦合的服务,这样可以降低开发难度、增强扩展性、便于敏捷开发。当前被越来越多的开发者推崇,很多互联网行业巨头、开源社区等都开始了微服务的讨论和实践。

微服务落地存在的问题

虽然微服务现在如火如荼,但对其实践其实仍处于探索阶段。很多中小型互联网公司,鉴于经验、技术实力等问题,微服务落地比较困难。

如著名架构师Chris Richardson所言,目前存在的主要困难有如下几方面:

单体应用拆分为分布式系统后,进程间的通讯机制和故障处理措施变的更加复杂。
系统微服务化后,一个看似简单的功能,内部可能需要调用多个服务并操作多个数据库实现,服务调用的分布式事务问题变的非常突出。
微服务数量众多,其测试、部署、监控等都变的更加困难。
随着RPC框架的成熟,第一个问题已经逐渐得到解决。例如springcloud可以非常好的支持restful调用,dubbo可以支持多种通讯协议。

对于第三个问题,随着docker、devops技术的发展以及各公有云paas平台自动化运维工具的推出,微服务的测试、部署与运维会变得越来越容易。

而对于第二个问题,现在还没有通用方案很好的解决微服务产生的事务问题。分布式事务已经成为微服务落地最大的阻碍,也是最具挑战性的一个技术难题。

参考文章:https://www.jianshu.com/p/ee4071d0c951

分布式事务常见概念

本地事务

我们先从本地事务(数据库事务)说起吧,因为这个是大家在日常工作都接触到,开发过程中都会用到的。
事务: 由一组操作构成的可靠的,独立的操作单元;具有ACID四大特性,分别为原子性,一致性,隔离性和持久性。
优点:本地事务由资源管理系本地自行管理;支持严格的ACID四大特性;高效,可靠;
缺点:多个数据源搞不定,不具备分布式事务处理能力。

分布式事务

幂等性

简单的说, 业务操作支持重试, 不会产生不利影响。
简单来说:重复调用多次产生的业务结果与调用一次产生的业务结果相同; 在分布式架构中,我们调用一个远程服务去完成一个操作,除了成功和失败以外,还有未知状态,那么针对这个未知状态,我们会采取一些重试的行为; 或者在消息中间件的使用场景中,消费者可能会重复收到消息。对于这两种情况,消费端或者服务端需要采取一定的手段,也就是考虑到重发的情况下保证数据的安全性。一般我们常用的手段

  1. 为消息额外增加唯一ID。
  2. 状态机实现幂等。
  3. 数据库唯一约束实现幂等。
  4. 通过tokenid的方式去识别每次请求判断是否重复。

事务补偿机制

在事务链中的任何一个正向事务操作, 都必须存在一个完全符合回滚规则的可逆事务。

柔性事务

刚性事务是指严格遵循ACID原则的事务, 例如单机环境下的数据库事务。

刚性事务

柔性事务是指遵循BASE理论的事务, 通常用在分布式环境中, 常见的实现方式有: 两阶段提交(2PC), TCC补偿型提交, 基于消息的异步确保型, 最大努力通知型。
通常对本地事务采用刚性事务, 分布式事务使用柔性事务。可以简称为是外柔内刚

分布式事务常见理论

ACID理论

原子性(Atomicity): 一个事务的所有系列操作步骤被看成是一个动作,所有的步骤要么全部完成要么一个也不会完成,如果事务过程中任何一点失败,将要被改变的数据库记录就不会被真正被改变。

一致性(Consistency): 数据库的约束 级联和触发机制Trigger都必须满足事务的一致性。也就是说,通过各种途径包括外键约束等任何写入数据库的数据都是有效的,不能发生表与表之间存在外键约束,但是有数据却违背这种约束性。所有改变数据库数据的动作事务必须完成,没有事务会创建一个无效数据状态,这是不同于CAP理论的一致性"consistency".

隔离性(Isolation): 主要用于实现并发控制, 隔离能够确保并发执行的事务能够顺序一个接一个执行,通过隔离,一个未完成事务不会影响另外一个未完成事务。

持久性(Durability): 一旦一个事务被提交,它应该持久保存,不会因为和其他操作冲突而取消这个事务。很多人认为这意味着事务是持久在磁盘上,但是规范没有特别定义这点。

CAP 理论

在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance) 这三个要素最多只能同时满足两个,不可兼得。其中,分区容忍性又是不可或缺的。所以另外两个仅能满足一个,即满足一致性与可用性只能选择其一。

一致性:分布式环境下,多个节点的数据是否强一致。
可用性:分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果。
分区容忍性:特指对网络分区的容忍性。

举例:Cassandra、Dynamo 等,默认优先选择 AP,弱化 C;HBase、MongoDB 等,默认优先选择 CP,弱化 A。

一致性

在分布式环境下,一致性是指数据在多个副本之间能否保持一致的特性。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一直的状态。
对于一个将数据副本分布在不同分布式节点上的系统来说,如果对第一个节点的数据进 行了更新操作并且更新成功后,却没有使得第二个节点上的数据得到相应的更新,于是在对第二个节点的数据进行读取操作时,获取的依然是老数据(或称为脏数 据),这就是典型的分布式数据不一致的情况。在分布式系统中,如果能够做到针对一个数据项的更新操作执行成功后,所有的用户都可以读取到其最新的值,那么 这样的系统就被认为具有强一致性。

可用性

可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。这里的重点是”有限时间内”和”返回结果”。

“有限时间内”是指,对于用户的一个操作请求,系统必须能够在指定的时间内返回对 应的处理结果,如果超过了这个时间范围,那么系统就被认为是不可用的。另外,”有限的时间内”是指系统设计之初就设计好的运行指标,通常不同系统之间有很 大的不同,无论如何,对于用户请求,系统必须存在一个合理的响应时间,否则用户便会对系统感到失望。

“返回结果”是可用性的另一个非常重要的指标,它要求系统在完成对用户请求的处理后,返回一个正常的响应结果。正常的响应结果通常能够明确地反映出队请求的处理结果,即成功或失败,而不是一个让用户感到困惑的返回结果。

分区容错性

分区容错性约束了一个分布式系统具有如下特性:分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。
网络分区是指在分布式系统中,不同的节点分布在不同的子网络(机房或异地网络) 中,由于一些特殊的原因导致这些子网络出现网络不连通的状况,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成了若干个孤立的区域。 需要注意的是,组成一个分布式系统的每个节点的加入与退出都可以看作是一个特殊的网络分区。

选择说明:
CA: 放弃分区容错性,加强一致性和可用性,其实就是传统的单机数据库的选择
AP: 放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性,这是很多分布式系统设计时的选择,例如很多NoSQL系统就是如此
CP: 放弃可用性,追求一致性和分区容错性,基本不会选择,网络问题会直接让整个系统不可用

参考文章:https://blog.csdn.net/xuxian6823091/article/details/81144775#%E6%9C%AC%E5%9C%B0%E4%BA%8B%E5%8A%A1

BASE理论

核心思想:

基本可用(Basically Available):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用;

软状态(Soft state):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性;

最终一致性(Eventual consistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态;

原子性(A)与持久性(D)必须根本保障;

为了可用性、性能与降级服务的需要,只有降低一致性( C ) 与 隔离性( I ) 的要求;

酸碱平衡(ACID-BASE Balance);

BASE 是对 CAP 中 AP 的一个扩展

参考资料:
https://www.jianshu.com/p/ee4071d0c951

分布式事务的方案模型

经典的 X/OpenDTP 事务模型

注:2PC、3PC的解决方案,都是属于经典的 X/OpenDTP 事务模型。

X/Open DTP(X/Open Distributed Transaction Processing Reference Model) 是X/Open 这个组织定义的一套分布式事务的标准,也就是定义了规范和 API 接口,由各个厂商进行具体的实现。这个标准提出了使用二阶段提交(2PC – Two-Phase-Commit)来保证分布式事务的完整性。后来 J2EE 也遵循了 X/OpenDTP 规范,设计并实现了 java 里的分布式事务编程接口规范-JTA

X/OpenDTP 角色:在 X/OpenDTP 事务模型中,定义了三个

  • AP: application, 应用程序,也就是业务层。哪些操作属于一个事务,就是 AP 定义的。
  • RM: Resource Manager,资源管理器。一般是数据库,也可以是其他资源管理器,比如数据库,消息队列,文件系统。
  • TM: Transaction Manager ,事务管理器、事务协调者,负责接收来自用户程序(AP)发起的 XA 事务指令,并调度和协调参与事务的所有 RM(数据库),确保事务正确完成。
    在分布式系统中,每一个机器节点虽然都能够明确知道自己在进行事务操作过程中的结果是成功还是失败,但却无法直接获取到其他分布式节点的操作结果。因此当一个事务操作需要跨越多个分布式节点的时候,为了保持事务处理的 ACID 特性,就需要引入一个“协调者”(TM)来统一调度所有分布式节点的执行逻辑,这些被调度的分布式节点被称为 AP。TM 负责调度 AP 的行为,并最终决定这些 AP 是否要把事务真正进行提交到(RM)。

完成事务操作主要有以下几个步骤:

  1. 参与分布式事务的应用程序(AP)先到 TM 上注册全局事务。

  2. 然后各个 AP 直接在相应的资源管理器(RM)上进行事务操作。

  3. 操作完成以后,各个 AP 反馈事务的处理结果给到 TM。

  4. TM 收到所有 AP 的反馈以后,通过数据库提供的 XA 接口进行数据提交或者回滚操作。

参考文章:https://www.cnblogs.com/wuzhenzhao/p/10338968.html

分布式事务一致性模型:

注:TCC两阶段补偿方案、基于消息的最终一致性方案、最大努力通知型 都是属于分布式事务一致性模型。

在 java 中,分布式事务主要的规范是 JTA/XA . JTA 是 java 的事务管理器规范,JTA 全称为 Java Transaction API, JTA 定义了一组统一的事务编程的接口,基于X/OpenDTP 规范设计的分布式事务编程接口规范。XA 是工业标准的 X/Open DTP规范,基于 JTA 规范的第三方分布式事务框架有 Jotm 和 Atomikos

  JOTM:JOTM (java open transaction manager)是 ObjectWeb 的一个开源 JTA 实现,提供 JTA 分布式事务的功能但是 JOTM 存在一个问题,在使用中不能自动 rollback,无论什么情况都 commit。

  Atomikos:与 JOTM 相比,Atomikos 更加稳定,原本 Atomikos 是商业项目,后来开源。论坛比较活跃,有问题可以随时解决。Atomikos 与SpringBoot集成参照 https://www.cnblogs.com/wuzhenzhao/p/10315130.html。

参考文章:https://www.cnblogs.com/wuzhenzhao/p/10338968.html

分布式事务的最佳实践?

先上结论, 再分别介绍分布式事务的各种实现方式.。

  1. 如果业务场景需要强一致性, 那么尽量避免将它们放在不同服务中, 也就是尽量使用本地事务, 避免使用强一致性的分布式事务。
  2. 如果业务场景能够接受最终一致性, 那么最好是使用基于消息的最终一致性的方案(异步确保型)来解决。
  3. 如果业务场景需要强一致性, 并且只能够进行分布式服务部署, 那么最好是使用TCC方案而不是2PC方案来解决。
    注意: 以下每种方案都有不同的适用场合, 需要根据实际业务场景来选择

分布式事务的常用解决方案

2PC即两阶段提交(two-phaseCommit)

方案介绍:

两阶段提交(Two Phase Commit, 2PC), 具有强一致性, 是CP系统的一种典型实现。
两阶段提交, 常见的标准是XA, JTA等. 例如Oracle的数据库支持XA.

适用场景

优点

  • 原理简单,实现很方便

缺点

  • 两阶段提交中的第二阶段, 协调者需要等待所有参与者发出yes请求, 或者一个参与者发出no请求后, 才能执行提交或者中断操作. 这会造成长时间同时锁住多个资源, 造成性能瓶颈, 如果参与者有一个耗时长的操作, 性能损耗会更明显。
  • 每一个阶段都是同步阻塞,会造成性能损耗。
  • 协调者存在单点问题,如果协调者在第二阶段出现故障,那么其他参与者会一直处于锁定状态。
  • 太过保守,任意一个节点失败都会导致数据回滚
  • 数据不一致问题: 在阶段二中,当协调者向所有的参与者发送 commit 请求后,发生了网络异常导致协调者在尚未发完 commit 请求之前崩溃,可能会导致只有部分的参与者接收到 commit 请求,剩下没收到 commit 请求的参与者将无法提交事务,也就可能导致数据不一致的问题.
  • 实现复杂, 不利于系统的扩展, 不推荐。

3PC

方案介绍:

3PC 协议主要用来解决 2PC 的同步阻塞问题的一种优化方案,3pc 分为 3 个阶段分别为:cancommit、Precommit、doCommit。和 2 阶段提交的区别在于:
(1) 在协调者和参与者中引入了超时机制,2pc 只有在协调者拥有超时机制,协调者在一定时间内没受到参与者的信息则默认为失败;
(2) 把 2 阶段提交的第一个阶段拆分成了两个步骤。
  cancommit 阶段:协调者向参与者发送 commit 请求,参与者如果可以提交就返回 yes 的响应,否则返回 No 的响应。这一阶段主要是确定分布式事务的参与者是否具备了完成commit 的条件,并不会执行事务操作。

  1. 询问参与者是否可以执行事务提交操作。
  2. 正常情况下只要能够顺利执行事务,就返回 yes 的响应,并进入预备状态。
      precommit 阶段:事务协调者根据参与者的反馈情况来决定是否继续执行事务的 precommit 操作,在这一个阶段,会有两种可能性,第一种是,在 cancommit 阶段所有参与者都反馈的是 yes,则会进行事务预执行。
  3. 协调者向参与者发送 precommit 请求。
  4. 参与者收到 precommit 请求后,执行事务操作,并把事务的 undo 和 redo 信息记录到事务日志中3. 返回事务的执行结果给到协调者,并等待最终的提交指令如果任意一个事务参与者在第一阶段返回了 no,则执行事务中断请求。
  5. 向所有事务参与者发送事务中断请求。
  6. 对于事务参与者来说,无论是收到协调者的中断请求,还是等待协调者新的指令之前出现超时,参与者都会中断事务。
      doCommit 阶段:这个阶段同样存在两种情况,正常情况下,precommit 都响应了 ack 给到协调者,那么协调者会发起事务提交请求。
  7. 协调者向所有参与者发送 docommit 请求。
  8. 参与者收到 docommit 请求后,执行事务提交操作,并释放所有事务资源。
  9. 事务提交以后返回 ack 给到协调者。
  10. 协调者收到所有参与者的响应后,完成事务。
      如果在 precommit 阶段,有参与者没有发送 ack 给到协调者,那么则执行事务中断指令。
  11. 协调者向所有参与者发送中断事务的请求。
  12. 参与者收到请求以后,利用在第二个阶段记录的 undo 信息来执行事务回滚操作。
  13. 向协调者发送 ack 消息,协调者收到消息以后,执行事务中断操作。

适用场景

优点

缺点

TCC (Try-Confirm-Cancle)

方案介绍

TCC, 是基于补偿型事务的AP系统的一种实现, 具有最终一致性。

优点

对比与前面提到的两阶段提交法, 有两大优势

  • TCC能够对分布式事务中的各个资源进行分别锁定, 分别提交与释放, 例如, 假设有AB两个操作, 假设A操作耗时短, 那么A就能较快的完成自身的try-confirm-cancel流程, 释放资源. 无需等待B操作. 如果事后出现问题, 追加执行补偿性事务即可.
  • TCC是绑定在各个子业务上的(除了cancle中的全局回滚操作), 也就是各服务之间可以在一定程度上”异步并行”执行.

缺点

适用场景

  • 严格一致性,适用强隔离性,一致性要求高的业务活动的场景
  • 执行时间短
  • 实时性要求高
    举例:红包、收付款业务。

注意事项

  • 事务管理器(协调器)这个节点必须以带同步复制语义的高可用集群(HAC)方式部署。
  • 事务管理器(协调器)还需要使用多数派算法来避免集群发生脑裂问题。

异步确保型(基于消息的最终一致性)

方案介绍

通过将一系列同步的事务操作变为基于消息执行的异步操作, 避免了分布式事务中的同步阻塞操作的影响
这个方案真正实现了两个服务的解耦, 解耦的关键就是异步消息和补偿性事务。

优点

消息数据独立存储,伸缩性好,降低与业务系统的耦合性;对最终一致性的时间敏感度比较高,降低业务被动方的实现成本

缺点

消息系统建设成本比较高,一次消息发送需要两次请求,业务处理服务需要给消息系统提供状态回查的接口。

适用场景

  • 执行周期较长
  • 实时性要求不高
    例如:
  • 跨行转账/汇款业务(两个服务分别在不同的银行中)。
  • 退货/退款业务。
  • 财务, 账单统计业务(先发送到消息中间件, 然后进行批量记账)。

注意事项

  • 消息中间件在系统中扮演一个重要的角色, 所有的事务消息都需要通过它来传达, 所以消息中间件也需要支持 HAC 来确保事务消息不丢失
  • 根据业务逻辑的具体实现不同,还可能需要对消息中间件增加消息不重复, 不乱序等其它要求

最大努力通知型

方案介绍

这是分布式事务中要求最低的一种, 也可以通过消息中间件实现, 与前面异步确保型操作不同的一点是, 在消息由MQ Server投递到消费者之后, 允许在达到最大重试次数之后正常结束事务.

业务活动 主动方,在完成业务处理之后,向业务活动的被动方发送消息,允许消息丢失; 业务活动的被动方根据定时策略,向业务活动主动方查询,回复丢失的业务消息。
适用于对业务最终一致性的时间敏感度低的场景。
https://blog.csdn.net/xuxian6823091/article/details/81144775#%E6%9C%AC%E5%9C%B0%E4%BA%8B%E5%8A%A1

优点

缺点

适用场景

交易结果消息的通知等

注意事项

基于Saga理论的解决方案

方案介绍

优点

缺点

适用场景

注意事项

参考例子

比较成熟的一个是华为开源并且托管在apache的项目 ServiceComb Pack

一些参考的链接:
gitee的地址:
https://gitee.com/servicecomb
https://gitee.com/servicecomb/ServiceComb-Saga/tree/master
https://gitee.com/servicecomb/ServiceComb-Saga/blob/master/docs/user_guide_zh.md
github的地址:
https://github.com/apache/servicecomb-pack
https://github.com/apache/servicecomb-pack/blob/master/docs/faq/en/how_to_use_mysql_as_alpha_backend_database.md
https://github.com/apache/servicecomb-pack/blob/master/docs/user_guide_zh.md
https://github.com/apache/servicecomb-pack/blob/master/docs/faq/en/how_to_use_mysql_as_alpha_backend_database.md

如何运行 ServiceComb Pack 参考
https://my.oschina.net/katkrazy/blog/1626190
https://www.jianshu.com/p/268dfc7e4a52
https://blog.csdn.net/ice166/article/details/89709726
https://blog.csdn.net/guotufu/article/details/80920215

完整微服务化示例:使用 Apache ServiceComb (incubating) 进行微服务开发、容器化、弹性伸缩
https://my.oschina.net/u/3823482/blog/1798732

分布式事务实现方案阿里巴巴fescar、华为servicecomb-pack对比分析 https://blog.csdn.net/douliw/article/details/88654076

eventuate-tram-sagas (《微服务架构设计模式》这本书的作者写的一个框架)

一些参考的链接:
github地址:
https://github.com/eventuate-tram/eventuate-tram-sagas
https://github.com/eventuate-tram/eventuate-tram-sagas
https://github.com/eventuate-tram/eventuate-tram-sagas-examples-customers-and-orders

EasyTransaction(也有saga理论有一定的应用)

一些参考的链接
github地址:
https://github.com/QNJR-GROUP/EasyTransaction

其它常见问题

接口如何保证幂等

参考文章,待整理
https://www.cnblogs.com/linjiqin/p/9678022.html
https://blog.csdn.net/sanyuedexuanlv/article/details/88373083
https://blog.csdn.net/Linjingke32/article/details/82726216
https://www.cnblogs.com/zhaopanpan/articles/9351170.html
https://blog.csdn.net/u011635492/article/details/81058153
https://blog.csdn.net/doujinlong1/article/details/81028923
https://blog.csdn.net/weixin_33882452/article/details/89658360
https://www.cnblogs.com/aoeiuv/p/5868137.html

事务补偿的接口该怎么写

参考文章,待整理
https://blog.csdn.net/myth_g/article/details/85003858

分布式事务 CAP 理解论证

参考文章,待整理
https://blog.csdn.net/weixin_40533111/article/details/85069536

参考文章

《这两天正在研究微服务架构中分布式事务的处理方案, 做一个小小的总结, 作为备忘. 如有错误, 欢迎指正!。。。里面介绍了很多东西,概念澄清、最佳实践、解决方案》
https://www.cnblogs.com/xifenglou/p/8440863.html

什么是幂等、经典的 X/OpenDTP 事务模型、2pc 提交(two -phaseCommit)、3PC
https://www.cnblogs.com/wuzhenzhao/p/10338968.html

本地事务、全局事务、Bsse理论、CAP理论、柔性事务 、X/Open DTP、CAP选择说明
https://blog.csdn.net/xuxian6823091/article/details/81144775#%E6%9C%AC%E5%9C%B0%E4%BA%8B%E5%8A%A1

正文到此结束
本文目录