mysql 的 redo log 写入是否正常需通过 show engine innodb status 查看 log sequence number 与 log flushed up to 的差值,并监控 innodb_os_log_written 和 innodb_os_log_fsyncs 增量;undo log 清理依赖最老活跃读视图,长事务会阻塞 purge;崩溃恢复先重放 redo log(前滚),再用 undo log 回滚未提交事务;二者协同由 innodb 自动调度,关键风险在于未结束的长事务。

怎么看 MySQL 的 redo log 写入是否正常
redo log 不是靠“查日志文件”来分析的,它默认不落盘为可读文本,而是由 InnoDB 管理的循环写入二进制文件(ib_logfile0、ib_logfile1)。想确认它是否在工作,得看运行时状态和写入压力反馈。
- 用
SHOW ENGINE INNODB STATUS\G查LOG小节,重点关注Log sequence number(当前 LSN)和Log flushed up to(刷到磁盘的 LSN),两者差距大说明刷盘滞后 - 监控
Innodb_os_log_written(累计写入字节数)每秒增量,配合Innodb_os_log_fsyncs(fsync 次数)看是否频繁刷盘——若写入量大但 fsync 很少,可能是innodb_flush_log_at_trx_commit=2在起作用 - 别直接用
hexdump或strings翻ib_logfile*,内容是结构化 binary,强行解析会误判;真要取证,用mysqlbinlog --base64-output=DECODE-ROWS配合 binlog 更靠谱
undo log 什么时候会被清理,为什么事务一提交就查不到旧版本了
undo log 不是随事务提交立刻删除的,它的生命周期取决于「最老的活跃读视图」(即未提交的事务或未释放的 consistent read snapshot)。InnoDB 用 purge thread 异步回收,但前提是没被任何事务需要。
- 长事务是 undo log 积压的头号原因:执行一个跑了 10 分钟的
SELECT(哪怕只是SELECT SLEEP(600)),所有在此期间产生的 undo 都不能清理 -
information_schema.INNODB_TRX里看TRX_STARTED和TRX_ROWS_MODIFIED,能快速定位“钉子户”事务 -
innodb_max_purge_lag是个软限制,它不会阻止新写入,只通过延迟INSERT/UPDATE/DELETE来减缓 purge 压力,别指望它解决根本问题
redo log 和 undo log 怎么协同保证崩溃恢复
崩溃恢复时,MySQL 启动阶段先重放 redo log(前滚,Redo Phase),把所有已提交但没写入数据页的变更补上;再根据 redo 中的事务状态,对未提交事务做 undo log 回滚(回滚,Undo Phase)。两者缺一不可,顺序也不能颠倒。
- 如果
innodb_log_file_size太小(比如默认 48MB),高并发写入容易触发频繁 checkpoint,导致 redo 循环覆盖过快,万一 crash 时最新 redo 还没刷盘,就会丢数据 - undo log 存在
system tablespace(5.7)或独立表空间(8.0+innodb_undo_tablespaces),但它不参与 crash recovery 的“重放”,只用于 rollback 和 MVCC——所以删错 undo 表空间会导致无法回滚、查询报错ERROR 1558 (HY000): Column count of mysql.user is wrong这类元数据异常 - 不要关
innodb_undo_log_truncate:它控制 undo 表空间自动截断,关了会导致 undo 占满磁盘且无法收缩
用 SELECT ... FOR UPDATE 时 undo log 和 redo log 谁先写
语句执行过程中,先生成 undo log 记录旧值(用于可能的回滚和 MVCC),再修改数据页并记 redo log(确保物理变更可重放)。这个顺序是硬编码在 InnoDB 事务流程里的,没法调换。
- 即使事务最终
COMMIT,undo log 也不会立即消失——只要还有其他事务需要读取该行的历史版本(比如开了REPEATABLE READ并早于本事务启动),它就得留着 - redo log 写入时机受
innodb_flush_log_at_trx_commit控制:1是每次 commit 都 fsync(安全但慢),0或2可能丢最近 1 秒事务,别在线上库瞎设 - 用
performance_schema.data_locks能看到当前哪些行被FOR UPDATE锁住,但看不到 undo 是否已分配——那部分在内存中,只有崩溃后从磁盘 recover 时才真正用到










