4. 状态持久化核心概念:状态机模型、Saga日志、事件溯源基础
在分布式事务鉴权拦截场景中,Saga 执行器需要可靠地记录每一步的进展,以便在节点崩溃、网络分区或鉴权失败后能够准确恢复。本章围绕三个核心概念展开:状态机模型定义 Saga 实例的生命周期;Saga 日志作为持久化的物理载体;事件溯源提供一种不可变的事件流重建思路。三者共同构成状态持久化的理论基石。
4.1 Saga 状态机模型
Saga 实例从创建到终结,其状态迁移遵循有限状态机(FSM)规则。每个 Saga 实例在任意时刻只处于一个确定状态,外部事件(如事务提交、补偿触发、超时)驱动状态转移。
核心状态定义: 以下状态是 Saga 持久化模型的最小公共集合,实际工程中可扩展。
| 状态 | 含义 | 可转移至 |
|---|---|---|
| CREATED | Saga 实例已创建,尚未执行任何步骤 | EXECUTING |
| EXECUTING | 正在按顺序执行正向事务步骤 | COMPENSATING, COMPLETED, FAILED |
| COMPENSATING | 某一步失败,正在执行逆向补偿操作 | COMPENSATED, FAILED |
| COMPLETED | 所有正向步骤成功执行完毕 | —(终态) |
| COMPENSATED | 所有补偿步骤成功执行完毕 | —(终态) |
| FAILED | 发生不可恢复错误,Saga 终止 | —(终态) |
鉴权拦截场景提示: 当鉴权 Token 过期或权限不足时,Saga 状态应从 EXECUTING 直接跳转至 COMPENSATING,并记录鉴权失败原因到日志中,而不是进入 FAILED 终态——因为补偿操作本身可能依赖新的鉴权凭证。
4.2 Saga 日志(Log)
Saga 日志是状态持久化的物理基础。每次状态迁移、步骤开始/完成、补偿触发,都会向日志中追加一条不可变记录。日志既是恢复的依据,也是审计追踪的原始数据源。
4.2.1 日志记录结构
每条 Saga 日志记录应包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| saga_id | UUID / String | Saga 实例全局唯一标识 |
| seq | Long | 日志序列号,单调递增 |
| event_type | Enum | 事件类型:STEP_STARTED / STEP_SUCCEEDED / STEP_FAILED / COMPENSATION_STARTED / COMPENSATION_SUCCEEDED / COMPENSATION_FAILED / SAGA_COMPLETED / SAGA_FAILED |
| step_name | String | 当前步骤名称(如 "deduct_balance") |
| payload | JSON | 步骤输入参数或补偿所需上下文 |
| auth_context | JSON | 鉴权上下文(Token、角色、权限快照) |
| timestamp | Long | 事件发生时间戳(毫秒) |
| version | Int | 乐观锁版本号,用于并发控制 |
鉴权拦截关键点:
auth_context 字段必须记录鉴权时刻的 Token 快照和权限集合。当 Saga 恢复重试时,如果原 Token 已过期,恢复逻辑应依据此字段判断是否需要重新获取鉴权凭证,而不是直接使用过期的 Token 重试。
4.2.2 日志写入策略
- 追加写入(Append-Only): 日志只追加,不修改、不删除。这保证了恢复时的线性一致性。
- 同步刷盘: 在返回客户端成功之前,必须确保日志已持久化到磁盘(如 WAL 机制)。
- 批量提交: 高并发场景下,可合并多个 Saga 事件的日志写入,减少 I/O 次数,但需保证每个 Saga 实例内部的 seq 严格递增。
- 索引加速: 对 saga_id + seq 建立联合索引,支持快速回放指定 Saga 的事件流。
4.3 事件溯源(Event Sourcing)基础
事件溯源将 Saga 日志提升为唯一的事实来源。Saga 实例的当前状态不是直接存储的,而是通过回放所有历史事件计算得出。这种模式天然适合 Saga 的恢复和审计需求。
4.3.1 事件溯源 vs. 状态快照
| 维度 | 事件溯源 | 状态快照 |
|---|---|---|
| 存储内容 | 不可变的事件流 | 当前状态的瞬时值 |
| 恢复方式 | 重放所有事件 | 直接读取快照 |
| 审计能力 | 完整历史可追溯 | 仅知当前状态 |
| 存储空间 | 随时间线性增长 | 固定大小 |
| 恢复速度 | 慢(需重放) | 快(直接读取) |
| 适用场景 | 需要审计、调试、复杂补偿 | 对延迟敏感、状态简单 |
工程实践建议: 采用混合模式——以事件溯源为主,定期生成状态快照(Snapshot)。恢复时先加载最近的快照,再重放快照之后的事件,兼顾恢复速度和历史完整性。
4.4 三者关系总结
状态机模型、Saga 日志、事件溯源并非独立概念,而是层层递进的关系:
- 状态机模型 定义了 Saga 实例应该如何迁移(行为规范)。
- Saga 日志 记录了 Saga 实例实际如何迁移(物理证据)。
- 事件溯源 提供了一种方法论,将日志视为唯一真相源,通过重放事件重建任意时刻的状态。
鉴权拦截场景落地: 当鉴权中间件拦截到过期 Token 时,Saga 执行器会写入一条
STEP_FAILED 事件(携带鉴权失败原因和原 Token 快照),状态机从 EXECUTING 迁移至 COMPENSATING。恢复时,事件溯源引擎重放日志,发现鉴权失败事件后,自动触发补偿步骤——整个过程无需额外的手动干预。