MySQL(3)-日志 (2)

由于InnoDB的redo log出现晚于binlog,且两者都用于crash safe,那么就需要保证binlog和redolog中数据的一致性,这里采用类似于分布式事务中的想法,采用两阶段提交的方式来保证一致性,流程如下(此时默认redo log写盘已经执行)

进入Prepare阶段,设置redo log为prepare

写入binlog cache

进入Commit阶段,设置redo log为commit

根据binlog的写盘策略,将binlog cahce写入binlog,策略有下面三种

0

每次提交写入到os cache

1

每次提交都直接写入bin log

N

每次都写入os cache,累计N个事务再fsync()

2)异常分析

写redo log宕机

这时可以根据已经落盘的undo log进行回滚

写binlog cache宕机

这时一致性未达成,根据undo log做回滚

提交后宕机

检查redo log中存储的最新事务号是否存在于binlog,如果不存在,将不存在的回滚

3.4 预写日志

预写日志(Write Ahead Log)即在修改磁盘内的数据页中的信息前,将修改信息先写入磁盘中的log文件,如redo log和bin log

这么做有以下优势

顺序io

由于redo log和binlog落盘时是顺序写入的,而如果直接修改磁盘中数据页中的数据,是随机io,效率非常低

并发量大

读写者互不阻塞

fsync调用次数少

相较于直接写入磁盘,WAL的fsync调用次数很少,无需每个事务都写盘

3.5 sync、fsync和fdatasync 3.5.0 延迟写

linux中为了减少磁盘io,在写入磁盘时会经历如下步骤

写入os cache

写入output queue

写入磁盘

只有当os cache满时,才会复制到output queue;只有output queue队首的数据会被写入到磁盘

3.5.1 sync

将数据同步到os cache,并不会等待到写入磁盘后返回,这需要update守护进程周期性调用sync将os cache输出到output queue保证写盘成功

3.5.2 fsync

对于某个文件的fd,调用fsync会在写盘成功后返回,写入的数据包括inode中的文件属性以及文件的数据部分

3.5.3 fdatasync

同样对于某个文件的fd,调用fdatasync会在写盘成功后返回,写入的数据只有文件的数据部分,不包括inode

3.6 double write和redo log 3.6.1 为何需要Doublewrite

buffer pool中的数据要写入到磁盘时,是以页为单位,如果写入过程出现宕机,那么就算有redo log也无法恢复,由于redo log每个页内记录的是逻辑日志,而逻辑日志需要保证表中的数据是完备且未改动的,这样where条件才不会失效,因而redo log并不能保证页面级别的crash safe

3.6.2 Doublewrite实现 1)组成

分为两部分

内存中的double write buffer

物理磁盘上共享表空间中连续的128个页,即2个区(extent),大小同样为2MB

2)机制

流程如下

每次脏页会先复制到double write buffer

分两次,每次1MB将页面信息书顺序写入到磁盘上的共享表空间

将buffer中的数据调用fsync离散写入磁盘

这样由于在磁盘的共享表空间中记录了页面的详细修改信息,就可以在同步页面到磁盘上时保证crash safe

# 参考

MySQL :: MySQL 5.7 Reference Manual :: 14.4 InnoDB Architecture

重要,知识点:InnoDB的插入缓冲 (qq.com)

为什么数据不会丢,InnoDB的Double Write,你必须知道 - 掘金 (juejin.cn)

MySQL--buffer pool、redo log、undo log、binlog_黄智霖的博客-CSDN博客

Write-Ahead Logging (sqlite.org)

redo log的被动刷盘机制 - 云+社区 - 腾讯云 (tencent.com)

Linux IO同步函数:sync、fsync、fdatasync | Byte_Liu's Blog (byteliu.com)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwyzgp.html