敲黑板:InnoDB的Double Write,你必须知道

作者:架构技术专栏
出处:
前序【敲黑板:InnoDB的Double Write,你必须知道】InnoDB引擎有几个重点特性 , 为其带来了更好的性能和可靠性:

  • 插入缓冲(Insert Buffer)
  • 两次写(Double Write)
  • 自适应哈希索引(Adaptive Hash Index)
  • 异步IO(Async IO)
  • 刷新邻接页(Flush Neighbor Page)
今天我们的主题就是 两次写(Double Write) , 先一句话概括下:
上一次我们讲过Insert Buffer 是用来提高存储引擎性能上的提升 , Double Write 就是为了在数据库崩溃恢复时保证数据不丢失的一个重要特性 , 保证了数据的可靠性 。
概念点
敲黑板:InnoDB的Double Write,你必须知道文章插图
如图 , 还是先来说几个基础的概念:
  • 数据库表空间由段(segment)、区(extent)、页(page)组成
  • 默认情况下有一个共享表空间ibdata1,如使用了innodb_file_per_table则每张表独立表空间(指存放数据、索引、插入缓冲bitmap页)
  • 段包括了数据段(B+树的叶子结点)、索引段、回滚段
  • 区 , 由连续的页组成 , 任何情况下每个区都为1M , 一个区中有64个连续页(16k)
  • 页 , 数据页(B-tree Node)默认大小为16KB
  • 文件系统一页 默认大小为4KB
  • 盘片被分为许多扇形的区域 , 每个区域叫一个扇区 , 硬盘中每个扇区的大小固定为512字节
  • 脏页 , 当数据从磁盘加载到缓冲池的数据页后 , 数据页内容被修改后 , 此数据页称为脏页
出现的问题通过上次讲的 重要 , 知识点:InnoDB的插入缓冲 我们知道 , 脏页会在某些场景下进行刷盘 , 将缓冲池内的脏页数据落地到磁盘 。
因为存储引擎缓冲池内的数据页大小默认为16KB , 而文件系统一页大小为4KB , 所以在进行刷盘操作时 , 就有可能发生如下场景:
敲黑板:InnoDB的Double Write,你必须知道文章插图
如图所示 , 数据库准备刷新脏页时 , 需要四次IO才能将16KB的数据页刷入磁盘 。
但当执行完第二次IO时 , 数据库发生意外宕机 , 导致此时才刷了2个文件系统里的页 , 这种情况被称为写失效(partial page write) 。
此时重启后 , 磁盘上就是不完整的数据页 , 就算使用redo log也是无法进行恢复的 。
注意:
  • redo log无法恢复数据页损坏的问题 , 恢复必须是数据页正常并且redo log正常 。
  • 这里要知道一点 , redo log中记录的是对页的物理操作 , 如偏移量600 , 写'xxxx'记录 。
  • 如果这个页本身已经发生了损坏 , 再对其进行重做是没有意义的
该怎么解决这个问题那应该怎么来解决这个问题呢?其实大家想一下就会有个大概的答案 , 就是给它搞个备份呗 。
如果写脏页的时候发生宕机 , 在重启后使用下备份先恢复下数据页在写磁盘就可以了 , 其实这就是 Double Write。
Double Write 出现千呼万唤始出来 , 为了防止我们可怜的数据被破坏 , InnoDB存储引擎提供了重要的Double Write 特性 , 避免了数据丢失的惨剧发生 。
下面我们来慢慢的来看看Double Write 到底是怎么提高可靠性的
Double Write 解决的问题在数据库进行脏页刷新时 , 如果此时宕机 , 有可能会导致磁盘数据页损坏 , 丢失我们重要的数据 。 此时就算重做日志也是无法进行恢复的 , 因为重做日志记录的是对页的物理修改 。
其实就是在重做日志前 , 用户需要一个页的副本 , 当写入失效发生时 , 先通过页的副本来还原该页 , 再进行重做 , 这就是double write 。
Double Write 架构
敲黑板:InnoDB的Double Write,你必须知道文章插图
如图 , 其实Double Write 分为了两个组成部分:
  • 内存中的double write buffer
  • 物理磁盘上共享表空间中连续的128个页 , 即2个区(extent) , 大小同样为2MB
可以看出 , 有了Double write后的脏页刷新流程就是多了几步操作:
  1. 在对缓冲池的脏页进行刷新时 , 并不直接写磁盘 , 而是会通过memcpy函数将脏页先复制到内存中的Double write buffer
  2. 通过Double write buffer再分两次 , 每次1MB顺序地写入共享表空间的物理磁盘上 , 然后马上调用fsync函数 , 同步磁盘 , 避免缓冲写带来的问题
Double write崩溃恢复
敲黑板:InnoDB的Double Write,你必须知道文章插图
如图 , 如果操作系统在将页写入磁盘的过程中发生了崩溃 , 在恢复过程中 , InnoDB存储引擎可以从共享表空间中的Double write中找到该页的一个副本 , 将其复制到表空间文件 , 再应用重做日志 。