什么是double write?
一部分是内存中的double write buffer ,大小为2MB(16k一个页,一共128个页)。
第二部分是磁盘共享表空间的128个数据页,在对脏页进行落盘的时候,并不是直接进行落盘,而是先复制到double write buffer,然后再分别写入到共享表空间,然后再写入表空间。
为什么要有双写机制?
页面的刷新会遇到部分写的问题,也就是说对于其中一个页面只写了一部分的内容,在数据库崩溃后,传统的数据库会使用redo log进行恢复,恢复的原理是通过redo对数据也进行重新进行物理操作,但是如果这个数据页本身发生了损坏,那innodb的页面大小是16KB,但是写入过程中只写了4KB(操作系统仅仅保证512字节写入的完整性),这个是时候因为页面不是完整的,因此不能通过redo来进行恢复。
Redo log中不包含完整的数据页(性能考虑),通常只包含对数据页的变更记录。
所以通过完好的原始数据页结合redo log中的记录,可以推断导出变更后的正确数据页,而一旦原始数据页损坏,则无法推导出正确的变更后的数据页。
redo恢复的前提条件是页是完整的。那么redo对其进行重做也是没有作用的,innodb的二次写,在写入的时候,创造了一个关于页的副本,这样即使在发生写失效后,也可以通过副本页,对还原重做。
双写是否会大大降低写性能?
通常不会,双写无疑会增加磁盘IO压力的,为了尽可能降低性能影响,双写在buffer落盘的时候,使用批量+顺序写的方式进行。假设要写入磁盘的数据页有64页,那么直接写数据文件会产生64次fsync,使用双写的情况下,假设双写Buffer落盘的批大小为64页,则落盘只需要1次fsync(总体fync加1),并且双写Buffer落盘是顺序写文件,也保障了文件写入的性能。所以通常情况下,使用双写并不会大大降低写性能。
5.7和8.0的区别
5.7

8.0

8.0的版本,double write 从共享表空间中独立出来。对于写性能,使用独立的文件还是共享表空间,并不影响顺序写这个特性。而批量写方面,在8.0.20之前,是每批64个Page, 8.0.20及之后的版本,则由参数innodb_doublewrite_pages确定,默认值等于innodb_write_io_threads(该参数的默认值为4)。
当存在大量数据需要落盘的情况,64和4的差异对比,无疑将后者的落盘次数增加了16倍,而落盘所对应的fsync操作是非常影响性能的。
所以自8.0.20开始的版本,将其设置为一个合理值显得极其重要(目前的默认配置显然是不合理的)。MySQL提供了两个状态值:Innodb_dblwr_pages_written、innodb_dblwr_writes,前者为累计的双写页数,后者为累计的双写次数。
两值的比例,可用于衡量innodb_doublewrite_pages设置是否合理,如果两值的比例经常接近innodb_doublewrite_page,并且磁盘的吞吐量明显低于磁盘的最佳性能表现,则表明innodb_doublewrite_page设置得过低,需要调大innodb_doublewrite_pages的值,避免影响性能。




