doublewrite buffer通过“先落副本、再写正本”的原子流程拦截partial page write:脏页先memcpy至2mb内存双写缓冲区,再分两次1mb顺序写入系统表空间连续区域并fsync落盘,最后才离散写入.ibd文件;崩溃时若页校验失败,即从双写区还原完整页再应用redo log。

Doublewrite Buffer 怎么拦住 partial page write?
它不是缓存,也不是性能优化层,而是一套「先落副本、再写正本」的原子保障流程。InnoDB 刷脏页时,不会直接把 16KB 页扔进 .ibd 文件——而是先 memcpy 到内存里的 doublewrite buffer(固定 128 个页,共 2MB),再把这整块内存分两次、每次 1MB,顺序写入系统表空间(ibdata1 或独立双写文件)中预留的连续区域(extend1 + extend2),调用 fsync() 确保落盘后,才开始向各自 .ibd 文件做离散写。
关键点在于:顺序 I/O 写双写区快且可靠;而它的存在让崩溃恢复多了一条路——启动时若发现某页 page checksum 失败,InnoDB 就去双写区找同一页号的副本;副本完整,就覆盖损坏页,再继续应用 redo log。
为什么 redo log 和 binlog 都救不了断裂页?
redo log 记录的是「对某页某 offset 执行了什么修改」,前提是该页结构完整、能解析出 page_no 和 LSN;断裂页连页头都可能错乱,redo 根本读不出上下文,直接跳过或报错。
binlog 更不相关:它只记录逻辑变更(如 UPDATE t SET x=1 WHERE id=5),不保存任何物理页副本,无法还原被撕裂的 16KB 结构。
没 doublewrite buffer,崩溃后唯一出路就是从备份恢复,且最近几秒事务必然丢失。
如何确认 doublewrite 实际在工作?
别只看配置文件里有没有 innodb_doublewrite = ON,运行时状态才作数:
- 执行
SHOW VARIABLES LIKE 'innodb_doublewrite';—— 必须返回ON - 执行
SHOW STATUS LIKE 'Innodb_dblwr%';,重点关注:Innodb_dblwr_writes(双写区写入次数)和Innodb_dblwr_pages_written(写入页数);两者长期为0,说明机制未触发,可能是实例刚启动、还没到 checkpoint,也可能是配置被忽略 - MySQL 8.0.20+ 中,若启用了
innodb_redo_log_capacity自动管理,Innodb_dblwr_writes可能延迟出现,等第一个 checkpoint 完成后才开始计数
关闭 doublewrite 的真实代价是什么?
它不是“可选开关”,而是数据完整性底线。现代 SSD 下关掉后写放大仅降 10%~15%,但风险陡增:
- 断电或 crash 后极易出现
InnoDB: Database page corruption on disk或mysqld fails to start with "Page directory corruption" - RAID、UPS、XFS
barrier都不能替代它:文件系统保证的是4KB块原子性,而 InnoDB 页是16KB,中间态仍可能残留 - MySQL 8.0.20+ 默认强制开启,且运行时
SET GLOBAL innodb_doublewrite = OFF会报错,除非满足极苛刻条件(如innodb_page_size = 16k且未启用crc32校验)
真正容易被忽略的点是:双写缓冲区大小是硬编码的 2MB(128 × 16KB),不可调;它也不随 innodb_buffer_pool_size 变化,更不依赖磁盘类型——只要用 InnoDB,它就在那儿,默默兜底。











