Seata的Undo Log存储机制是什么?
Seata的Undo Log(回滚日志) 是其AT(Auto Transaction)模式实现分布式事务回滚的核心机制,通过记录数据变更前的快照(before image)和变更后的状态(after image),支持分支事务的回滚操作。以下是其存储机制的详细解析:
Undo Log的核心设计
1. 存储位置
- 与业务数据同库:每个分支事务的Undo Log存储在业务数据库的单独表中(默认表名为
undo_log
),与业务数据共用同一个本地事务,确保原子性。 - 隔离性保障:通过业务SQL和Undo Log在同一个本地事务中写入,实现"业务操作+日志记录"的原子提交。
2. 表结构设计
undo_log
表包含关键字段:
CREATE TABLE undo_log (id BIGINT(20) AUTO_INCREMENT PRIMARY KEY,branch_id BIGINT(20) NOT NULL, -- 分支事务IDxid VARCHAR(100) NOT NULL, -- 全局事务IDcontext VARCHAR(128) NOT NULL, -- 上下文信息(如序列化格式)rollback_info LONGBLOB NOT NULL, -- 回滚信息(压缩后的二进制数据)log_status INT(11) NOT NULL, -- 日志状态(0-正常,1-已删除)log_created DATETIME NOT NULL, -- 创建时间log_modified DATETIME NOT NULL, -- 修改时间UNIQUE KEY ux_undo_log (xid, branch_id) -- 唯一索引
);
3. 日志内容(rollback_info)
采用自定义二进制格式存储,包含:
- Before Image:SQL更新前的数据快照(用于回滚恢复)。
- After Image:SQL更新后的数据状态(用于脏写校验)。
- SQL类型(INSERT/UPDATE/DELETE)。
- 表元数据(表名、列信息)。
示例:更新操作
UPDATE product SET stock=90 WHERE id=1
的Undo Log
- Before Image:
{id:1, stock:100}
- After Image:
{id:1, stock:90}
Undo Log的生命周期
1. 写入阶段(事务开启)
2. 回滚阶段(全局事务失败)
3. 清理阶段(全局事务提交后)
- 异步删除:TC通知提交成功后,RM异步删除对应的Undo Log。
- 定时清理:内置线程定期扫描删除状态为
log_status=1
(已删除)的过期日志。
关键技术细节
1. 数据序列化
- 支持多种序列化协议:默认使用Kryo,可选FST、Hessian等。
- 压缩存储:对
rollback_info
字段使用ZIP压缩,减少磁盘占用。
2. 脏写检测(关键安全机制)
在回滚前执行:
SELECT stock FROM product WHERE id=1; -- 当前数据库值
- 正常情况:当前值 = After Image(stock=90)→ 执行回滚。
- 脏写发生:当前值 ≠ After Image(如其他事务修改为stock=80)→ 中止回滚并告警。
3. 逆向SQL生成逻辑
原SQL类型 | 逆向SQL生成规则 | 示例 |
---|---|---|
INSERT | 生成DELETE语句 | DELETE FROM product WHERE id=1 |
DELETE | 生成INSERT语句(用Before Image) | INSERT INTO product(id,stock) VALUES(1,100) |
UPDATE | 生成UPDATE回退到Before Image | UPDATE product SET stock=100 WHERE id=1 |
设计优势与挑战
优势
- 原子性保证:业务数据与Undo Log同库同事务写入,避免单点故障。
- 高效回滚:直接解析Undo Log生成逆向SQL,无需扫描全量日志。
- 轻量无侵入:对业务代码透明,仅需代理DataSource。
挑战与规避
问题 | 解决方案 |
---|---|
日志膨胀 | 异步删除 + 定期清理机制 |
主键冲突(INSERT回滚) | 使用Before Image中的完整数据生成INSERT |
高并发写入竞争 | 分支事务串行化(TC全局锁协调) |
跨数据库兼容性 | 抽象SQL模板(不同数据库方言动态适配) |
生产实践建议
- 表结构优化:
- 对
undo_log
表分区(按log_created
时间)提升查询效率。 - 使用SSD存储降低日志读写延迟。
- 对
- 参数调优:
# 调整日志批量删除大小(默认1000) client.undo.log.batch.delete.size=2000 # 缩短日志保留时间(默认7天) client.log.exception.retry.period=259200000 # 3天
- 监控重点:
- Undo Log表大小增长趋势。
- 回滚操作耗时(检测脏写频率)。
- 异步删除线程堆积情况。
总结:Undo Log的核心价值
Seata通过Undo Log实现了分布式事务的回滚能力,其设计精髓在于:
- 与业务数据同库存储 → 利用本地事务保证日志与业务的原子性。
- 前后镜像完整记录 → 支持精确逆向数据恢复。
- 异步清理机制 → 平衡性能与存储开销。
这一机制虽牺牲了部分存储空间,但换来了分布式事务的高可用性与数据最终一致性,是AT模式能在生产环境广泛应用的关键基石。