分布式事务

基本概念

事务

由若干个操作组成的一个完整的逻辑过程

本地事务

A原子性:事务的所有操作要么全部成功要么全部失败

I 隔离性:多个事务间的执行互不干扰,有不同的隔离级别

D持久性:事务完成后对数据的变更会持久化到硬盘上

C一致性:事务完成后,数据的完整性没有被破坏;这是事务的目的,上面三者是实现方式

使用常见的关系型数据库可以保证本地事务的数据一致性

分布式事务

分布式事务主要有以下几种情况:

  • 远程调用其他服务修改数据
  • 跨数据库实例
  • 多个jvm进程访问同一个数据库实例

关系型数据库能保证分布式事务的数据一致性?

不能

案例1:

begin;
1数据库操作  #成功
2远程调用   #成功
3数据库操作  #失败,回滚
commit;
#此时远程调用2并不会被回滚,数据发生了不一致

案例2:

begin;
1数据库操作 #成功
2远程调用   #成功,但网络问题未及时返回应答,回滚
commit;
# 此时操作2已经执行,也发生了数据不一致

解决方案

2PC方案

理论基础

2PC即两阶段提交协议,将整个事务流程分为准备阶段提交阶段

事务过程由事务管理器参与者组成,事务管理器负责决策整个分布式事务的提交和回滚,事务参与者负责自己本地事务的提交和回滚

两个阶段:

  1. 准备阶段:事务管理器向每个参与者发送Prepare消息,每个数据库参与者在本地执行事务,并写本地的Undo/Redo日志,此时事务没有提交
  2. 提交阶段:如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送回滚消息,否则发送提交消息;最后参与者各自执行本地事务的提交或回滚,并释放锁;

具体实现

2PC方案是基于关系型数据库实现的

  • XA方案
  • seta方案

TCC方案

理论基础

TCC是Try、Confirm、Cancel三个词语的缩写,分别为业务的三个操作/阶段

Try:业务检查、预留资源(检查金额、冻结金额)

Confirm:确认提交阶段,Try阶段所有分之事务都成功即可执行Confirm(把冻结的金额归零),TCC情况下认为Confirm一定不会失败

Cancel:回滚阶段,Try阶段有操作失败时需要执行补偿操作(把冻结的金额放回余额中)

这种方案对业务代码的侵入性非常强,要编写很多额外的代码,可能还需要添加表的字段(冻结金额)

可靠消息最终一致性方案

基本概念

当事务的发起方执行事务成功后会发出一条消息消费者一定能接收消息并处理事务成功,该方法强调的是本地事务执行成功就一定会发出消息!消费者也一定会消费该消息保证数据一致性(最终一致)!

此方案需要解决三个问题:

  • 本地事务与消息发出的原子性

    begin ;
     1. 数据库操作
     2. 发送MQ #超时回滚,但消息已经发出,不一致!
    commit;
    
  • 事务参与方接收消息的可靠性(不漏消费)

  • 消息重复消费,方法幂等

具体实现

本地消息表方案

新加一张消息日志表,定时扫描表中未发送的消息给MQ,消费端消费完之后修改日志状态

#使用数据库保证新增用户与消息日志的原子性
begin;
新增用户
新增对应日志
commit;

image-20220920164817946

RocketMQ事务消息方案

RocketMQ 4.3之后实现了完整的事务消息,将本地消息表移动到MQ内部,解决Producer端的消息发送与本地事务执行的原子性问题;

image-20220920165331674

关键流程:

  1. 发送半消息到MQ,此时消费者不可消费
  2. 本地事务执行完发送commitrollback消息,对应半消息变为可消费/被删除
  3. 半消息未收到commit时,会执行事务回查,检查事务是否提交

最大努力通知方案

系统A调用B,系统B会将结果通知给A

  • 最大努力,也就是重试若干次,失败就不通知了
  • 会提供一个接口,A调用该接口完成校验

image-20220920171159984

参考资料:

Q.E.D.


记录 • 分享 • 日常