MySQL 崩溃后能恢复数据,靠的就是 redo log
—— 它不是备份,也不是 binlog,而是 InnoDB 引擎写在磁盘上的“操作快照”,专为崩溃恢复而生。
为什么 MySQL 崩溃后不丢已提交的数据?
因为事务提交前,InnoDB 已经把这次修改的物理操作(比如“页号 123 的偏移量 456 处写入值 0xABC”)记到了
redo log文件里,并按配置刷了盘。崩溃重启时,InnoDB 会自动扫描
ib_logfile*,重放所有已提交但还没写进数据文件(
.ibd)的变更。 这个过程叫 recovery(前滚恢复),只重做,不回滚 它不依赖 binlog;即使
log_bin关着,
redo log照样工作 恢复粒度是
page(16KB),不是行或 SQL,所以它是物理日志
怎么确认 redo log 正在起作用?
看 MySQL 启动日志里有没有类似
InnoDB: Doing recovery: scanned up to log sequence number XXX这样的输出。这是最直接的证据——说明 InnoDB 正在读
redo log并重放。 启动时若发现
ib_logfile0和
ib_logfile1存在且非空,InnoDB 就一定会执行 recovery 可通过
SHOW ENGINE INNODB STATUS\G查看
LOG小节,关注
Log sequence number和
Log flushed up to是否接近 手动模拟崩溃:用
kill -9杀掉 mysqld 进程,再启动,观察 error log —— 不会报数据不一致,就是
redo log在兜底
哪些配置直接影响崩溃恢复效果?
关键就两个参数,改错一个,可能让“已提交事务丢失”变成现实:
innodb_flush_log_at_trx_commit = 1(默认):每次
COMMIT都调用
fsync()刷盘 → 最安全,但有性能开销
innodb_flush_log_at_trx_commit = 0:只每秒刷一次,崩溃可能丢 1 秒内所有已提交事务
innodb_log_file_size:单个
ib_logfile*大小,默认 48MB。太小会导致频繁 checkpoint,拖慢写入;太大则 recovery 时间变长(要重放更多日志)
innodb_log_files_in_group:默认为 2,即
ib_logfile0+
ib_logfile1循环写。不能直接删文件扩容,必须停库、改配置、删旧文件、重启
常见误操作和坑
很多人以为“只要开了 binlog 就不怕丢数据”,其实完全错误 —— binlog 是 server 层日志,不参与崩溃恢复。真正扛住断电/kill -9 的,只有
redo log。 误删
ib_logfile*文件?MySQL 启动失败,报错
Cannot find or open table mysql/engine_cost类似信息 —— 因为 InnoDB 检查不到合法日志头,拒绝启动 升级 MySQL 后没重建
ib_logfile*?可能因格式不兼容导致 recovery 失败或静默跳过,数据实际已损坏 把
innodb_flush_log_at_trx_commit设成 0 或 2,又没配主从复制 + binlog 备份,等于主动放弃 ACID 中的 D(Durability) 误以为
redo log能恢复误删表 —— 它只记录页级修改,不存 SQL,也不支持闪回;删表是 DDL,哪怕没提交也立刻落盘,
redo log不管这事
真正要靠
redo log活命的场景,从来不是“我手抖删了数据”,而是“服务器突然断电”“宿主机宕机”“容器被 OOM kill”。它不聪明,但足够可靠——前提是别动它的刷盘策略和文件结构。
