前言
前面我们解析了InnoDB磁盘结构中的表空间、数据字典、双写缓冲区。
本文我们继续探究磁盘结构中剩余的几个核心组件:重做日志(redo log)、撤销日志(undo log)、二进制日志(binlog)
一、重做日志 ( redo log )
- WAL(Write-Ahead Logging)机制
WAL 的全称是 Write-Ahead Logging ,中文称预写式日志 ( 日志先行 ) ,是一种数据安全写入机制。 就是先写日志,然后再写入磁盘,这样既能提高性能又可以保证数据的安全性。 Mysql 中的 redo log 就是采用 WAL 机制。
为什么使用WAL ?
磁盘的写操作是随机IO ,比较耗性能,所以如果把每一次的更新操作都先写入 log 中,那么就成了 顺序写操作,实际更新操作由后台线程再根据 log 异步写入。这样对于 client 端,延迟就降低了。并 且,由于顺序写入大概率是在一个磁盘块内,这样产生的 io 次数也大大降低。所以 WAL 的核心在于 将随机写转变为了顺序写 ,降低了客户端的延迟,提升了吞吐量 .
- redo log基本概念
InnoDB引擎对数据的更新,是先将更新记录写入 redo log 日志,然后会在系统空闲的时候或者是 按照设定的更新策略再将日志中的内容更新到磁盘之中。这就是所谓的预写式技术( Write Ahead logging )。这种技术可以大大减少 IO 操作的频率,提升数据刷新的效率。
redo log:被称作重做日志 , 包括两部分:一个是内存中的日志缓冲: redo log buffer ,另一
个是磁盘上的日志文件: redo log file 。
mysql 每执行一条 DML 语句,先将记录写入 redo log buffer ( redo 日志记录的是事务对数据库做 了哪些修改 ) 。后续某个时间点再一次性将多个操作记录写到 redo log file 。当故障发生致使内存 数据丢失后, InnoDB 会在重启时,经过重放 redo ,将 Page 恢复到崩溃之前的状态 通过 Redo log 可以实现事务的持久性 。
- Redo log数据落盘流程
将内存中的数据页持久化到磁盘,需要下面的两个流程来完成 :
- 脏页落盘机制 脏页是指修改了Buffer Pool 中的数据页后 , 导致了内存中的数据页和磁盘中的数据页不一致 , 这时就出现 了脏页。当进行数据页的修改操作时: 首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。页从缓冲 池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为 CheckPoint 的机制刷新回磁盘。checkpoint机制思考一下这个场景:如果重做日志可以无限地增大,同时缓冲池也足够大,那么是不需要将缓冲池中页的新版本刷新回磁盘。因为当发生宕机时,完全可以通过重做日志来恢复整个数据库系统中的数据到宕 机发生的时刻。Checkpoint( 检查点 ) 技术主要解决以下几个问题:1. 缩短数据库的恢复时间2. 缓冲池不够用时,将脏页刷新到磁盘3. 重做日志不可用时,刷新脏页。脏页落盘的时机 采用CheckPoint检查点机制 以下机制都可通过参数控制
- redo log 持久化
缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统缓冲区( OS Buffer ) 。因此 redo log buffer 写入 redo logfile 实际上是先写入 OS Cache ,然后再通过系统调用 fsync() 将其刷到 redo log file.
Redo Buffer 持久化到 redo log 的策略,可通过 Innodb_flush_log_at_trx_commit 设置:
一般建议选择取值2,因为 MySQL 挂了数据没有损失,整个服务器挂了才会损失1秒的事务提交数据
- redo log日志格式
物理日志VS 逻辑日志
- 物理日志: 记录的是每一个page页中具体存储的值是多少,在这个数据页上做了什么修改. 比 如: 某个事物将系统表空间中的第100个页面中偏移量为1000处的那个字节的值1改为2.
- 逻辑日志: 记录的是每一个page页面中具体数据是怎么变动的,它会记录一个变动的过程或 SQL语句的逻辑, 比如: 把一个page页中的一个数据从1改为2,再从2改为3,逻辑日志就会记录1->2,2->3这个数据变化的过程.
redo日志属于物理日志, 只是记录一下事务对数据库做了哪些修改。
- redo log日志类型
redo log根据在页面中写入数据的多少 , 将 redo 日志划分为几种不同的类型 (MySQL5.7 中有 53 种类 型 ) 。
- MLOG_1BYTE (type=1) : 表示在页面的某个偏移量处写入1字节的redo日志类型。
- MLOG_2BYTE (type=2) : 表示在页面的某个偏移量处写入2字节的redo日志类型。
- MLOG_4BYTE (type=4) : 表示在页面的某个偏移量处写入 4字节 的redo日志类型。
- MLOG_8BYTE (type=8) : 表示在页面的某个偏移量处写入8字节的redo日志类型。
- MLOG_WRITE_STRING (