分布式事务

ACID

  • 原子性(Atomicity)

    一系列的操作整体不可拆分,要么同时成功,要么同时失败

  • 一致性(Consistency)

    对数据的一组特定约束必须始终成立(一致性(在 ACID 意义上)是应用程序的属性)

  • 隔离性(Isolation)

    事务的执行是相互独立的,它们不会相互干扰,一个事务不会看到另一个正在运行过程中的事务的数据

  • 持久性(Durabilily)

    一个事务完成之后,事务的执行结果必须是落盘在数据库持久

CAP

  • 一致性(Consistency)

    线性一致性,即所有节点在同一时间看到的数据是一样的

  • 可用性(Availability)

    在集群中一部分节点故障后,非故障的节点在合理的时间内返回合理的响应(保证返回正确的结果)

  • 分区容错性(Partition tolerance)

    系统能够在节点之间发生网络分区(Partition)的情况下仍然能够正常运行。在分布式系统中,网络无法100%可靠,分区其实是一个必然现象

分布式事务方案

分布式事务是为了解决分布式系统中的共识(数据一致性问题),保证分布式系统中的数据最终一致性。

在分布式系统中,事务提交必须是不可撤销的 —— 事务提交之后,你不能改变主意,并追溯性地中止事务。这个规则的原因是,一旦数据被提交,其结果就对其他事务可见,因此其他客户端可能会开始依赖这些数据。

2PC

sequenceDiagram
    participant coordinator as 协调者
    participant Alice
    participant Bob

    activate coordinator
    coordinator->>coordinator: 生成 t_id=1

    Note left of coordinator: I. 准备阶段
    par 
        coordinator->>Alice: Prepare(t_id=1)
        activate Alice
        Alice->>Alice: 锁定资源
        Alice-->>coordinator: Success
        deactivate Alice
    and 
        coordinator->>Bob: Prepare(t_id=1)
        activate Bob
        Bob->>Bob: 锁定资源
        Bob-->>coordinator: Success
        deactivate Bob
    end

    Note left of coordinator: II. 提交阶段
    par 
        coordinator->>Alice: Commit(t_id=1)
        activate Alice
        Alice->>Alice: 应用更改,释放资源
        Alice-->>coordinator: Success
        deactivate Alice
    and 
        coordinator->>Bob: Commit(t_id=1)
        activate Bob
        Bob->>Bob: 应用更改,释放资源
        Bob-->>coordinator: Success
        deactivate Bob
    end

    deactivate coordinator

两阶段提交(two-phase commit)有两个关键点:当参与者投票 “是” 时,它承诺它稍后肯定能够提交(尽管协调者可能仍然选择放弃);以及一旦协调者做出决定,这一决定是不可撤销的。这些承诺保证了 2PC 的原子性(单节点原子提交将这两个事件合为了一体:将提交记录写入事务日志)。

3PC

sequenceDiagram
    participant coordinator as 协调者
    participant Alice
    participant Bob

    activate coordinator
    coordinator->>coordinator: 生成 t_id=1

    Note left of coordinator: I. 准备阶段
    par 
        coordinator->>Alice: Prepare(t_id=1)
        activate Alice
        Alice->>Alice: 检查资源
        Alice-->>coordinator: Success
        deactivate Alice
    and 
        coordinator->>Bob: Prepare(t_id=1)
        activate Bob
        Bob->>Bob: 检查资源
        Bob-->>coordinator: Success
        deactivate Bob
    end

    Note left of coordinator: II. 预提交阶段
    par 
        coordinator->>Alice: Precommit(t_id=1)
        activate Alice
        Alice->>Alice: 锁定资源
        Alice-->>coordinator: Success
        deactivate Alice
    and 
        coordinator->>Bob: Precommit(t_id=1)
        activate Bob
        Bob->>Bob: 锁定资源
        Bob-->>coordinator: Success
        deactivate Bob
    end

    Note left of coordinator: III. 提交阶段
    par 
        coordinator->>Alice: Commit(t_id=1)
        activate Alice
        Alice->>Alice: 应用更改,释放资源
        Alice-->>coordinator: Success
        deactivate Alice
    and 
        coordinator->>Bob: Commit(t_id=1)
        activate Bob
        Bob->>Bob: 应用更改,释放资源
        Bob-->>coordinator: Success
        deactivate Bob
    end

    deactivate coordinator

三阶段提交(three-phase commit)相对于二阶段提交(2PC)有两个改进:引入了超时机制,以防止协调者在第二阶段失败时永远阻塞(超时自动提交,但也有可能造成数据不一致);将2PC的准备阶段拆分为两个阶段,这个阶段是重负载的操作(降低失败成本)。

XA

XA(eXtended Architecture)是两阶段提交(2PC)协议的一个实现,是一种分布式事务处理的标准协议,用于确保多个资源管理器(Resource Manager)之间的事务一致性。偏数据层面,通常由数据库内部支持。

TCC

sequenceDiagram
    participant Coordinator as 协调者
    participant ServiceA as 服务A
    participant ServiceB as 服务B

    Note over Coordinator,ServiceB: 事务开始
    Coordinator->>ServiceA: Try
    ServiceA-->>Coordinator: Try 成功/失败
    Coordinator->>ServiceB: Try
    ServiceB-->>Coordinator: Try 成功/失败


    alt 所有服务 Try 成功
        Coordinator->>+ServiceA: Confirm
        ServiceA-->>-Coordinator: Confirm 成功/失败
        Coordinator->>+ServiceB: Confirm 
        ServiceB-->>-Coordinator: Confirm 成功/失败
    else 至少一个服务 Try 或 Confirm 失败
        Coordinator->>+ServiceA: Cancel
        ServiceA-->>-Coordinator: Cancel 响应
        Coordinator->>+ServiceB: Cancel
        ServiceB-->>-Coordinator: Cancel 响应
    end

    Note over Coordinator,ServiceB: 事务结束

TCC(Try-Confirm-Cancel)是一种补偿性事务模式,它通过明确的三个阶段来保证分布式事务的一致性和可靠性。应用层面,适用于需要跨多个服务进行分布式事务处理的场景。

SAGA

sequenceDiagram
    participant S as SAGA
    participant T1 as 事务1
    participant T2 as 事务2
    participant C1 as 补偿事务1
    participant C2 as 补偿事务2

    Note over S, C2: SAGA 开始
    S->>T1: 执行事务1
    T1-->>S: 成功
    S->>T2: 执行事务2
    T2-->>S: 失败

    alt 向后补偿
        S->>C1: 执行补偿事务1
        C1-->>S: 成功
    else 向前补偿
        S->>T2: 继续执行事务2
        T2-->>S: 成功
    end
    Note over S, C2: SAGA 结束

Saga模式将一个大型事务拆分为多个小的、离散的事务片段,每个片段都具有自己的本地事务和补偿操作。应用层面。

本地消息表

sequenceDiagram
    participant A as 服务A
    participant LocalDB as 本地数据库
    participant MQ as 消息队列
    participant B as 服务B

    A->>LocalDB: 开始事务
    A->>LocalDB: 执行业务逻辑
    A->>LocalDB: 写入消息到本地消息表
    LocalDB->>A: 提交事务
    A->>MQ: 发送消息
    MQ->>B: 消息到达服务B
    B->>B: 处理消息
    B->>A: 确认消息处理完成
    A->>LocalDB: 更新本地消息

本地消息表事务(Local Message Table Transaction)是一种可靠消息事务机制,核心思想就是将分布式事务拆分成本地事务进行处理。

综合对比

分布式事务解决方案
方案 类型 性能 开发成本 优缺点
2PC 强一致 单点、性能低、同步阻塞
3PC 强一致 性能低
XA 强一致 资源需要支持XA协议
TCC 最终一致 需要协调应用逻辑,复杂性高
SAGA 最终一致 需要协调应用逻辑,复杂性高
本地消息表 最终一致 没有MQ可以使用定时任务