ShardingJDBC 14_分布式事务

137 阅读7分钟

1 分布式事务理论

  • CAP(强一致性),对于共享数据系统,最多只能同时拥有CAP其中的两个,任意两个都有其适应的场景。
选项描述
C(consistence)所有的节点上的数据时刻保持同步
A(availiblity)每个请求都能接受到一个响应,无论响应成功或失败
P(partition tolerance)系统应该能持续提供服务,即使系统内部有消息丢失
  • BASE(最终一致性), BASE 是指: 基本可用(Basically Available)、 软状态( Soft State)、 最终一致性( Eventual Consistency)。

它的核心思想是即使无法做到强一致性(CAP 就是强一致性),但应用可以采用适合的方式达到最终一致性。

2 分布式事务模式

了解了分布式事务中的强一致性和最终一致性理论,下面介绍几种常见的分布式事务的解决方案。

2.1 2PC模式(强一致性)

2PC 是 Two-Phase Commit 缩写,即两阶段提交,就是将事务的提交过程分为两个阶段来进行处理。事务的发起者称协调者,事务的执行者称参与者。协调者统一协调参与者执行。

阶段1:准备阶段,协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待所有参与者答复。各参与者执行事务操作,但不提交事务,将 undo 和 redo 信息记入事务日志中。如参与者执行成功,给协调者反馈 yes;如执行失败,给协调者反馈 no。

阶段2:提交阶段,如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(rollback)消息;否则,发送提交(commit)消息。

2PC 方案实现起来简单,实际项目中使用比较少,主要因为以下问题: 

  • 性能问题:所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,容易导致性能瓶颈。 
  • 可靠性问题:如果协调者存在单点故障问题,如果协调者出现故障,参与者将一直处于锁定状态。 
  • 数据一致性问题:在阶段2 中,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致。

2.2 3PC模式(强一致性)

3PC (三阶段提交),是两阶段提交的改进版本,与两阶段提交不同的是,引入超时机制。同时在协调者和参与者中都引入超时机制。三阶段提交将两阶段的准备阶段拆分为 2 个阶段,插入了一个preCommit 阶段,解决了原先在两阶段提交中,参与者在准备之后,由于协调者或参与者发生崩溃或错误,而导致参与者无法知晓处于长时间等待的问题。如果在指定的时间内协调者没有收到参与者的消息则默认失败。

阶段1:

canCommit,协调者向参与者发送 commit 请求,参与者如果可以提交就返回 yes 响应,否则返回 no 响应。 

阶段2:

preCommit,协调者根据阶段1 canCommit 参与者的反应情况执行预提交事务或中断事务操作。 参与者均反馈 yes:

协调者向所有参与者发出 preCommit 请求,参与者收到 preCommit 请求后,执行事务操作,但不提交;将 undo 和 redo 信息记入事务日志 中;

各参与者向协调者反馈 ack 响应或 no 响应,并等待最终指令。任何一个参与者反馈 no或等待超时:协调者向所有参与者发出 abort 请求,无论收到协调者发出的 abort 请求,或者在等待协调者请求过程中出现超时,参与者均会中断事务。 

阶段3:

doCommit 该阶段进行真正的事务提交,根据阶段2 preCommit反馈的结果完成事务提交或中断操作。 相比2PC模式,3PC模式降低了阻塞范围,在等待超时后协调者或参与者会中断事务。避免了协调者单点问题,阶段3 中协调者出现问题时(比如网络中断等),参与者会继续提交事务。

2.3 XA模式(强一致性)

XA是由 X/Open 组织提出的分布式事务的规范,是基于两阶段提交协议。 XA规范主要定义了全局事务管理器(TM)和局部资源管理器(RM)之间的接口。目前主流的关系型数据库产品都是实现了XA接口。

image.png

XA之所以需要引入事务管理器,是因为在分布式系统中,从理论上来说,两台机器,理论上无法达到一致的状态,需要引入一个单点进行协调。由全局事务管理器管理和协调的事务,可以跨越多个资源(数据库)和进程。 事务管理器用来保证所有的事务参与者都完成了准备工作(第一阶段)。如果事务管理器收到所有参与者都准备好的消息,就会通知所有的事务都可以提交了(第二阶段)。

MySQL 在这个XA事务中扮演的是参与者的角色,而不是事务管理器。

2.4 TCC模式(最终一致性)

TCC(Try-Confirm-Cancel)的概念,最早是由 Pat Helland 于 2007 年发表的一篇名为《Lifebeyond Distributed Transactions:an Apostate’s Opinion》的论文提出。

TCC 是服务化的两阶段编程模型,其 Try、Confirm、Cancel 3个方法均由业务编码实现: 

  • Try 操作作为一阶段,负责资源的检查和预留; 
  • Confirm 操作作为二阶段提交操作,执行真正的业务; 
  • Cancel 是预留资源的取消。

image.png

TCC 模式相比于 XA,解决了如下几个缺点: 

  • 解决了协调者单点,由业务应用发起并完成这个业务活动。业务活动管理器可以变成多点,引入集群。 
  • 同步阻塞:引入超时机制,超时后进行补偿,并且不会锁定整个资源,将资源转换为业务逻辑形式,粒度变小。 
  • 数据一致性,有了补偿机制之后,由业务活动管理器控制一致性。

3 Sharding-JDBC整合XA数据源

3.1 原理

XAShardingSphereTransactionManager 为 Apache ShardingSphere 的分布式事务的 XA 实现类。它主要负责对多数据源进行管理和适配,并且将相应事务的开启、提交和回滚操作委托给具体的 XA 事务管理器。

ShardingSphere整合XA事务时,分离了XA事务管理和连接池管理,这样接入XA时,可以做到对业务的零侵入。

ShardingSphere 支持以下功能: 

  • 支持数据分片后的跨库XA事务; 
  • 两阶段提交保证操作的原子性和数据的强一致性; 
  • 服务宕机重启后,提交/回滚中的事务可自动恢复; 
  • SPI机制整合主流的XA事务管理器,默认Atomikos; 
  • 同时支持XA和非XA的连接池; 
  • 提供 spring-boot 和 namespace 的接入端。

image.png

3.2 具体的实现过程

3.2.1 开启全局事务

XAShardingSphereTransactionManager将调用具体的 XA 事务管理器开启 XA 全局事务,以 XID 的形式进行标记。

3.2.2 执行真实分片SQL

XAShardingSphereTransactionManager 将数据库连接所对应的 XAResource 注册到当前 XA 事务中之后,事务管理器会在此阶段发送 XAResource.start 命令至数据库。数据库在收到XAResource.end 命令之前的所有 SQL 操作,会被标记为 XA 事务。

XAResource1.start       ## 开始阶段执行
statement.execute("sql1");  ## 模拟执行一个分片SQL1
statement.execute("sql2");  ## 模拟执行一个分片SQL2
XAResource1.end        ## 提交阶段执行

示例中的sql1和sql2将会被标记为 XA 事务。

3.2.3 提交或回滚事务

XAShardingSphereTransactionManager 在接收到接入端的提交命令后,会委托实际的 XA 事务管理进行提交动作, 事务管理器将收集到的当前线程中所有注册的 XAResource,并发送 XAResource.end 指令,用以标记此 XA 事务边界。

接着会依次发送 prepare 指令,收集所有参与 XAResource 投票:

  • 若所有 XAResource 的反馈结果均为正确,则调用 commit 指令进行最终提交;
  • 若有任意 XAResource 的反馈结果不正确,则调用 rollback 指令进行回滚。

在事务管理器发出提交指令后,任何 XAResource 产生的异常都会通过恢复日志进行重试,以保证提交阶段的操作原子性,和数据强一致性。

```
XAResource1.prepare      ## ack: yes
XAResource2.prepare      ## ack: yes
XAResource1.commit
XAResource2.commit

XAResource1.prepare      ## ack: yes
XAResource2.prepare      ## ack: no
XAResource1.rollback
XAResource2.rollback
```