wal是innodb实现crash-safe的强制前提:修改buffer pool前必须先将物理修改写入redo log,由innodb_flush_log_at_trx_commit=1保障日志强持久化,否则无法满足acid中的durability。

WAL 不是“可选优化”,而是 InnoDB 实现 Crash-Safe 的强制前提:没写 redo log,就不允许改内存页。
WAL 本质就是 innodb_flush_log_at_trx_commit 控制的那条铁律
它不是抽象概念,而是由具体参数驱动的硬性流程约束。InnoDB 在修改 Buffer Pool 中任意一个数据页前,必须先把该修改的物理描述(比如“page 1234,offset 56,从 0x01 写成 0x02”)追加写入 ib_logfile0 或 ib_logfile1 —— 这就是 WAL 的落地动作。
常见错误现象:innodb_flush_log_at_trx_commit=0 时,事务提交后立即断电,大概率丢失已提交数据;=2 时,若操作系统崩溃(而非 MySQL 进程崩溃),也可能丢 1 秒内提交的数据。
- 这个参数只影响 redo log 的刷盘时机,不影响日志是否生成 —— 日志总归会先于数据页修改而产生
- 值为
1(默认)才真正满足 ACID 中的 Durability:fsync 到磁盘才算事务提交完成 - 不要混淆
sync_binlog:binlog 是 Server 层日志,不参与 crash recovery,仅用于主从和归档
Crash-Safe 依赖的是 redo log + doublewrite buffer + checkpoint 三者协同
单独靠 WAL 日志不能完成恢复,必须配合其他机制。崩溃重启后,InnoDB 启动阶段会做两件事:一是从最近的 checkpoint 开始重放 redo log(recovery),二是用 doublewrite buffer 校验并修复可能被部分写坏的页面(partial page write)。
容易踩的坑:innodb_doublewrite=OFF 在某些云盘或文件系统上看似能提升写性能,但一旦发生页断裂(partial write),redo log 无法修复损坏页,直接导致数据页不可读 —— Crash-Safe 彻底失效。
- checkpoint 并非固定时间点,而是由脏页比例、LSN 差距、后台线程调度共同决定
- redo log 文件大小(
innodb_log_file_size)太小会导致频繁 checkpoint,放大随机 IO;太大则 recovery 时间变长 - MySQL 8.0+ 中,
innodb_redo_log_capacity取代了旧参数,但底层逻辑未变
为什么不能用 binlog 替代 redo log 实现 Crash-Safe
因为 binlog 是逻辑日志,记录的是 SQL 文本或行变更事件,且写入时机在事务提交的末尾(甚至异步),不满足“先写、再改、强制落盘”的 WAL 要求。崩溃时,binlog 可能根本没写完,或写完但对应的数据页尚未更新,无法保证一致性。
典型错误操作:关闭 innodb_flush_log_at_trx_commit,只靠 sync_binlog=1 来“保数据”—— 这只能保主从一致,完全不防单机崩溃。
- redo log 是物理日志,按数据页维度记录,恢复快、无歧义
- binlog 是逻辑日志,跨引擎通用,但恢复需重放 SQL,可能因函数、触发器、外键等引入不确定性
- 二者必须配合使用(如 XA 两阶段提交),但角色绝不互换
真正关键的不是“有没有日志”,而是“日志是否在数据修改前持久化”。很多线上事故源于对 innodb_flush_log_at_trx_commit 的误调,或把 binlog 的可靠性错当成 crash recovery 能力 —— 这两类误解,比参数本身更难排查。











