缓冲区管理

持久化与缓冲区管理

Buffer Pool | 缓冲池

事务提交后,InnoDB 首先在缓冲池中找到对应的页,把事务更新到缓冲区中;缓冲区把脏页拷贝到 double write buffer,double wirte buffer 把脏页刷新到 double write 磁盘(这也是一次顺序 IO),再把脏页刷新到数据文件中。当然缓冲池中还有其他组件,也非常重要,如插入缓冲,该缓冲区是为了高效维护二级非唯一索引所做的优化,把多次 IO 转化为一次 IO 来达到快速更新的目的。

如果说 Insert Buffer 带给 InnoDB 存储引擎的是性能上的提升,那么 double write 带给 InnoDB 存储引擎的是数据页的可靠性。当发生数据库宕机时,可能 InnoDB 存储引擎正在写入某个页到表中,而这个页只写了一部分,比如 16KB 的页,只写了前 4KB,之后就发生了宕机,这种情况被称为部分写失效(partial page write)。在 InnoDB 存储引擎未使用 doublewrite 技术前,曾经出现过因为部分写失效而导致数据丢失的情况。有经验的 DBA 也许会想,如果发生写失效,可以通过重做日志进行恢复。这是一个办法。但是必须清楚地认识到,重做日志中记录的是对页的物理操作,如偏移量 800,写'aaaa'记录。如果这个页本身已经发生了损坏,再对其进行重做是没有意义的。这就是说,在应用(apply)重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是 double write。

双写缓冲

缓冲池刷新脏页面到磁盘时,首先把它们写到双写缓冲,然后再把它们写到所属的数据区域中;InnoDb 用双写缓冲来避免页没写完整所导致的数据损坏。从缓冲池中拷贝页到 double_write_buffer,double_write_buffer 刷新到 double_write(共享表空间),再调 fsync() 同步磁盘。

Log Buffer | 日志缓冲

InnoDB 使用日志来减少事务提交时的开销,因为日志记录了事务,就无须在每个事务提交时把缓冲池中的脏块刷新到磁盘;因为刷新缓冲池到磁盘一般是随机 IO。

InnoDB 的日志缓冲有两个重要的参数:

  • innodb_log_buffer_size 日志缓冲区大小(5.6 默认 8M,一般不需要设置太大,除非有 BLOB 字段)

  • innodb_flush_log_at_trx_commit 这是 InnoDB 刷新事务日志的策略参数,默认为 1。刷新策略值: 0, 一秒钟刷新一次,事务提交时,不做任何操作.(可能丢失 1 秒钟事务数据);1, 每次事务都提交刷新到持久化存储(默认&最安全);2, 每次提交时把日志缓冲写到日志文件,但并不刷新。

1 和 3 的区别是: mysql 进程挂了,3 不会丢事务. 服务器断电或者挂了, 都丢失事务. 把缓冲写到日志是简单的把数据从 INNODB 的内存缓冲转移到操作系统缓冲。