bigywater.tech
MySQL / InnoDB · 68

Doublewrite Buffer

确认本机磁盘上真实存在doublewrite文件,再用真实的写入测试验证这套机制到底是逐页写入还是按批打包写入。

4MB+12MB
本机真实存在的两个doublewrite磁盘文件
约11页/批
doublewrite历史累计的真实平均打包大小

做的事:先看这个东西在磁盘上是不是真实存在

代码SELECT @@innodb_doublewrite; SHOW STATUS LIKE 'Innodb_dblwr%';

验证:磁盘上真实能找到doublewrite文件

实测 · 本机磁盘真实输出
$ ls -la /opt/homebrew/var/mysql/*.dblwr
#ib_16384_0.dblwr    4194304 字节 (4MB)
#ib_16384_1.dblwr   12582912 字节 (12MB)

@@innodb_doublewrite: ON

文件名里的16384正是InnoDB页大小(16KB),这两个文件真实是doublewrite机制专用的连续磁盘区域——脏页在被写到它们各自真正归属的、分散在数据文件各处的位置之前,会先真实完整地写进这块连续区域一份,用来在真实发生断电或者崩溃、导致某个页面写到一半(torn page)时,能从这份完整的副本里恢复出该页真实完整的样子。

验证:真实测一次写入,计数器涨了多少

实测 · 本机执行输出
测试前累计:  Innodb_dblwr_pages_written = 475   Innodb_dblwr_writes = 43
(真实跑一次全表更新,等待脏页被刷盘)
测试后累计:  Innodb_dblwr_pages_written = 476   Innodb_dblwr_writes = 44

历史累计的比例:475页 / 43批 ≈ 每批平均约11个页面
这次测试真实只贡献了1页1批,但把它放进历史累计的比例里看(约11页/批),能看出doublewrite真实不是"每写一个脏页就单独跑一趟磁盘",而是把这段时间内攒下来的多个脏页打包成一批,一次性顺序写进doublewrite区域,再逐个刷到它们各自真正的位置——这样设计是为了摊薄doublewrite带来的额外I/O开销:如果每个页面都单独触发一次doublewrite写入,相当于把所有写入的I/O次数直接翻倍;把多个页面打包成一批,doublewrite区域这一步的顺序写入开销就被真实分摊到了更多页面上。innodb_doublewrite默认是开启的,本文也没有在这台共享实例上真实关闭它去对比性能差异,因为doublewrite关系到崩溃后页面完整性的保障,不该在一台还跑着别的真实业务库的实例上冒这个险。

分步演示:doublewrite文件和计数器的真实对照

每一步都是本文上面用真实磁盘检查和SHOW STATUS跑出来的原始结果。

doublewrite真实是按批写入,不是逐页写入
这一步新验证的数字

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),真实的doublewrite磁盘文件 + Innodb_dblwr_*状态变量
    • 没有验证:真实关闭doublewrite后崩溃场景下的行为对比,出于对共享实例数据安全的顾虑没有测试
    京ICP备2026067502号-1京公网安备11010502063487号