4. 分布式事务画布架构:整体架构图、核心组件与交互流程

分布式事务画布(Distributed Transaction Canvas)是一种用于描述、设计和实现分布式事务的通用架构模型。它将事务的协调、执行与状态持久化抽象为三个核心角色,并通过标准化的交互流程保证跨节点数据的一致性。本章将详细阐述画布的整体架构、核心组件及其交互流程。

4.1 画布整体架构图

分布式事务画布采用分层与角色分离的设计思想。顶层为事务发起方(Application/Client),中间层为协调器(Coordinator),底层为参与者(Participant)与日志存储(Log Store)。所有组件通过定义良好的接口进行通信,形成一个可插拔、可观测的事务处理框架。

分布式事务画布整体架构图 事务发起方 (Application / Client) 协调器 (Coordinator) 参与者 A (Participant) 参与者 B (Participant) 日志存储 (Log Store) 发起全局事务 Prepare / Commit / Rollback Prepare / Commit / Rollback 写入事务日志 写入事务日志 记录事务状态 说明: 协调器是事务的“大脑”,负责决策;参与者是“手脚”,负责执行本地操作;日志存储是“记忆”,保证故障可恢复。

4.2 核心组件详解

画布架构由三个核心组件构成,每个组件承担明确的职责,并通过 Go 接口进行契约化定义。

4.2.1 协调器(Coordinator)

协调器是分布式事务的决策中心。它负责接收应用的事务请求,驱动参与者执行两阶段提交(2PC)或三阶段提交(3PC)协议,并在故障时根据日志进行恢复决策。

  • 职责:事务生命周期管理、参与者调度、超时处理、故障恢复。
  • 关键接口:Begin()、Prepare()、Commit()、Rollback()。
  • 状态机:维护事务从 Init → Prepared → Committed / Aborted 的状态转换。

4.2.2 参与者(Participant)

参与者是事务的执行单元,通常对应一个数据库、消息队列或微服务。它必须能够响应协调器的指令,并保证本地操作的原子性。

  • 职责:执行本地事务分支、记录 undo/redo 日志、返回执行结果。
  • 关键接口:Prepare()、Commit()、Rollback()。
  • 幂等性:参与者接口必须支持幂等调用,以应对网络重试。

4.2.3 日志存储(Log Store)

日志存储是事务的持久化基石。它记录事务的每一个关键状态变更,确保在协调器或参与者崩溃后,系统能够根据日志恢复到一致状态。

  • 职责:持久化事务日志、提供日志查询与回放能力。
  • 关键接口:WriteLog()、ReadLog()、DeleteLog()。
  • 存储后端:通常基于本地文件、etcd、MySQL 或对象存储实现。
设计要点: 协调器与参与者之间的通信必须考虑网络分区和超时。建议在 Go 接口中为每个 RPC 调用增加 context.Context 参数,以便传递超时和取消信号。

4.3 核心组件接口对比

下表对比了三个核心组件在 Go 接口层面的关键方法及其语义:

组件 接口方法 输入参数 输出结果 语义说明
协调器 Begin(ctx, txID) 上下文、事务ID 错误码 开启一个新全局事务
协调器 Prepare(ctx, txID) 上下文、事务ID 准备结果 通知所有参与者进入准备阶段
参与者 Prepare(ctx, branchID) 上下文、分支ID 准备结果 执行本地事务分支,锁定资源
参与者 Commit(ctx, branchID) 上下文、分支ID 错误码 提交本地事务分支,释放资源
参与者 Rollback(ctx, branchID) 上下文、分支ID 错误码 回滚本地事务分支,恢复数据
日志存储 WriteLog(ctx, logEntry) 上下文、日志条目 错误码 持久化一条事务日志
日志存储 ReadLog(ctx, txID) 上下文、事务ID 日志列表 读取指定事务的所有日志记录

4.4 交互流程:两阶段提交(2PC)

画布架构中最经典的交互流程是两阶段提交。该流程将事务提交分为“准备阶段”和“提交阶段”,确保所有参与者要么全部提交,要么全部回滚。

4.4.1 阶段一:准备(Prepare)

  1. 应用调用协调器的 Begin() 开启事务。
  2. 协调器向所有参与者发送 Prepare 请求,询问是否可以提交。
  3. 每个参与者执行本地事务分支(但不提交),记录 undo/redo 日志,并锁定资源。
  4. 参与者将准备结果(Yes/No)返回给协调器。

4.4.2 阶段二:提交或回滚(Commit / Rollback)

  1. 协调器收集所有参与者的准备结果。
  2. 如果所有参与者都返回 Yes,协调器向所有参与者发送 Commit 指令。
  3. 如果任一参与者返回 No 或超时,协调器向所有参与者发送 Rollback 指令。
  4. 参与者收到指令后,执行最终的提交或回滚操作,并释放资源。
  5. 协调器将最终事务状态写入日志存储。
两阶段提交(2PC)交互时序图 应用 协调器 参与者A 参与者B Begin(txID) Prepare(txID) Prepare(txID) 执行本地事务 执行本地事务 Yes Yes 决策:Commit Commit(txID) Commit(txID) 提交本地事务 提交本地事务 Ack Ack 写日志
实践建议: 在 Go 实现中,协调器向参与者发送 Prepare 请求时应使用并发 goroutine 调用,并设置合理的超时时间(如 5 秒)。使用 sync.WaitGroup 或 errgroup.Group 来收集所有参与者的响应。

4.5 故障恢复与日志回放

当协调器或参与者在事务执行过程中崩溃时,画布架构依赖日志存储进行恢复。恢复流程如下:

  1. 协调器重启后,首先从日志存储读取所有未完成的事务日志。
  2. 对于处于 Prepared 状态的事务,协调器向所有参与者重新发送 Commit 或 Rollback 指令(根据之前记录的决策)。
  3. 参与者收到重复指令时,根据本地日志判断是否已经执行过,保证幂等性。
  4. 所有事务达到最终状态(Committed / Aborted)后,协调器清理日志。
注意: 日志存储本身必须是高可用的。如果日志存储丢失数据,整个分布式事务系统将无法保证一致性。生产环境中建议对日志存储进行多副本部署。

4.6 本章小结