mysql事务日志(redo log、undo log)与恢复机制

来源:这里教程网 时间:2026-02-28 20:43:50 作者:

redo log 是什么,为什么不能只靠 binlog 做崩溃恢复

MySQL 崩溃后能恢复到最近一次提交的状态,靠的不是

binlog
,而是
redo log
。因为
binlog
是逻辑日志、追加写、不保证刷盘时机,且只记录“执行了什么 SQL”,无法精确还原页级变更;而
redo log
是物理日志、循环写、强制刷盘(受
innodb_flush_log_at_trx_commit
控制),记录的是“某个数据页的某个偏移位置改成了什么值”,可精准重放。

常见错误现象:把

innodb_flush_log_at_trx_commit=0
用于生产,机器掉电后大量事务丢失——这不是 bug,是配置明确放弃
redo log
持久性保障的结果。

innodb_flush_log_at_trx_commit=1
:每次事务提交都
fsync
到磁盘,最安全,性能开销最大
=2
:写入 OS 缓存即返回,每秒
fsync
一次,断电可能丢 1 秒数据
=0
:只写内存,依赖后台线程刷盘,崩溃可能丢大量事务

undo log 存在哪,怎么支撑 MVCC 和回滚

undo log
不是独立文件,而是存在
ibdata1
(或独立表空间)里的段(
UNDO LOG SEGMENT
),由
ROLLBACK SEGMENT
管理。它记录事务修改前的数据镜像,既用于事务回滚,也供其他事务做一致性读(
READ COMMITTED
/
REPEATABLE READ
隔离级别下构造快照)。

容易踩的坑:

long running transaction
会阻塞
undo log
的清理(
purge
线程无法回收其占用的空间),导致
ibdata1
持续膨胀,甚至触发
ERROR 1114 (HY000): The table is full

innodb_max_purge_lag
可控 purge 延迟,但治标不治本,需先定位长事务
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60
查找运行超 60 秒的事务
undo tablespace
支持独立文件(MySQL 5.6+ 可配
innodb_undo_tablespaces
),便于监控和清理

崩溃恢复时 redo log 和 undo log 怎么协作

MySQL 启动时自动执行崩溃恢复(crash recovery),分两阶段:

1. Redo Phase:按 <code>redo log</code> 重放所有已提交但未刷盘的页变更(前滚,Roll Forward)  
2. Undo Phase:扫描 <code>undo log</code>,对未提交事务执行回滚(回滚段中标记为 ACTIVE 的事务)

关键点在于:恢复顺序不可逆——必须先重放再回滚。否则未提交事务的中间状态会被固化,破坏原子性。

典型问题:如果

redo log
文件损坏(如磁盘坏道导致部分
ib_logfile0
读取失败),MySQL 启动直接报错
InnoDB: Error: log file ib_logfile0 is corrupted
,无法继续恢复;此时只能从备份 +
binlog
补日志,或启用
innodb_force_recovery
(风险极高,仅限导出数据)。

如何验证当前事务日志状态是否健康

不要等崩溃才查日志,日常应关注几个核心指标:

检查
redo log
写入压力:
SHOW GLOBAL STATUS LIKE 'Innodb_os_log_written';
对比历史值,突增说明写负载高或刷盘慢
确认
undo
空间使用:
SELECT TABLESPACE_NAME, FILE_SIZE, ALLOCATED_SIZE FROM INFORMATION_SCHEMA.FILES WHERE FILE_TYPE = 'UNDO LOG';
观察活跃回滚段:
SELECT * FROM information_schema.INNODB_ROLLBACK_SEGMENTS WHERE STATE = 'ACTIVE';
查看最近一次 checkpoint 位置:
SHOW ENGINE INNODB STATUS\G
中的
Log sequence number
Last checkpoint at
差值过大(如 > 1GB)说明刷盘滞后

真正麻烦的从来不是日志本身,而是日志背后暴露的事务模型缺陷——比如一个更新语句没加索引导致全表扫描锁住整张表,进而拖垮整个 undo 清理链路。这时候调日志参数只是掩耳盗铃。

相关推荐