4. 分布式事务画布架构:整体架构图、核心组件与交互流程
分布式事务画布(Distributed Transaction Canvas)是一种用于描述、设计和实现分布式事务的通用架构模型。它将事务的协调、执行与状态持久化抽象为三个核心角色,并通过标准化的交互流程保证跨节点数据的一致性。本章将详细阐述画布的整体架构、核心组件及其交互流程。
4.1 画布整体架构图
分布式事务画布采用分层与角色分离的设计思想。顶层为事务发起方(Application/Client),中间层为协调器(Coordinator),底层为参与者(Participant)与日志存储(Log Store)。所有组件通过定义良好的接口进行通信,形成一个可插拔、可观测的事务处理框架。
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)
- 应用调用协调器的
Begin()开启事务。 - 协调器向所有参与者发送
Prepare请求,询问是否可以提交。 - 每个参与者执行本地事务分支(但不提交),记录 undo/redo 日志,并锁定资源。
- 参与者将准备结果(Yes/No)返回给协调器。
4.4.2 阶段二:提交或回滚(Commit / Rollback)
- 协调器收集所有参与者的准备结果。
- 如果所有参与者都返回 Yes,协调器向所有参与者发送
Commit指令。 - 如果任一参与者返回 No 或超时,协调器向所有参与者发送
Rollback指令。 - 参与者收到指令后,执行最终的提交或回滚操作,并释放资源。
- 协调器将最终事务状态写入日志存储。
实践建议: 在 Go 实现中,协调器向参与者发送 Prepare 请求时应使用并发 goroutine 调用,并设置合理的超时时间(如 5 秒)。使用
sync.WaitGroup 或 errgroup.Group 来收集所有参与者的响应。
4.5 故障恢复与日志回放
当协调器或参与者在事务执行过程中崩溃时,画布架构依赖日志存储进行恢复。恢复流程如下:
- 协调器重启后,首先从日志存储读取所有未完成的事务日志。
- 对于处于 Prepared 状态的事务,协调器向所有参与者重新发送
Commit或Rollback指令(根据之前记录的决策)。 - 参与者收到重复指令时,根据本地日志判断是否已经执行过,保证幂等性。
- 所有事务达到最终状态(Committed / Aborted)后,协调器清理日志。
注意: 日志存储本身必须是高可用的。如果日志存储丢失数据,整个分布式事务系统将无法保证一致性。生产环境中建议对日志存储进行多副本部署。