mysql 两次写

366 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情 >>

mysql 两次写

1. 为什么要有两次写

数据页需要可靠性

2. 背景或者是要解决的问题

partial page write

因为InnoDB的PageSzie一般是16KB,数据效验和将数据写入磁盘也是一Page为单位进行操作的。在断电的情况下,并不能保证这一操作的原子性 ,存在部分新数据部分老数据的情况。

  • 为什么redo log恢复不了:mysql在恢复的过程中是检查page的checksum,checksum就是page的最后事务号,发生partial page write(部分页失效) 问题时,page已经损坏,找不到该page中的事务号。在innodb看来这样的数据页是无法通过当前的checksum验证的,就无法恢复。
  • 解决:double write buffer 在写数据页之前先把这个数据页写到一块独立的物理文件位置,再写到数据页。这样宕机重启的时候,如果出现数据页损坏,那么在应用redolog之前还能通过该页的副本来还原改也,然后再进行redo log重做

2. 概述和构造

简单来说就是InnoDB进行脏页刷新的时候,并不是直接写回磁盘,而是先将脏页复制到内存中的一个区域,然后再分两次顺序的写入磁盘

构造:

​ 1)一部分是内存中的doublewrite buffer,大小为2MB ​ 2)另一部分是物理磁盘上共享表空间中的连续128页,即两个区,大小同样为2MB(这里可以称为doubwite页)

double write

  • 当mysql将脏数据flush到data file的时候, 先使用memcopy 将脏数据复制到内存中的double write buffer 。
  • 之后通过double write buffer再分2次,每次写入1MB到共享表空间
  • 然后马上调用fsync函数,同步到磁盘上,避免缓冲带来的问题,在这个过程中,doublewrite是顺序写,开销并不大,在完成doublewrite写入后,在将double write buffer写入各表空间文件,这时是离散写入。
  • 如果发生了极端情况(断电),InnoDB再次启动后,发现了一个Page数据已经损坏,那么此时就可以从doublewrite buffer中进行数据恢复了。

在这里插入图片描述

3. 优点

  • 由于doublewrite页的物理空间是连续的,所以写的时候开销并不是很大
  • 如果是刷新脏页写入磁盘的时候宕机了,那么就直接通过doublewrite页进行恢复就行了
  • 如果是写doublewrite页宕机了,就可以通过重做日志恢复,重新写doublewrite buffer

dw的思路就是在覆盖磁盘上的数据前,先将Page的内容写到磁盘上的double write buffer,持久化,然后再将Page的内容覆盖到磁盘上原来的数据。

4. 副作用

  1. double write带来写负载,导致系统有更多的fsync操作,降低mysql的整体性能

    1. 但是double write buffer 写入磁盘共享表空间的这个过程是顺序写,性能非常高,影响不大
    2. 通过监控double write的工作负载可以知道,3<<64,系统的写压力并不高
  2. 关闭double write适合的场景

    1. 海量的DML
    2. 不惧怕数据损坏和丢失
    3. 系统写负载成为主要负载
  3. 为什么没有把double write里面的数据写到data page里面呢?

    double write里面的数据是连续的,如果直接写到data page里面,而data page的页又是离散的,写入会很慢。double write里面的数据没有办法被及时的覆盖掉,导致double write的压力很大;短时间内可能会出现double write溢出的情况。