Redo log
Redolog是重做日志。使用了WAL技术,WAL的全称是write-head logging。该技术的关键点就是先写日志,再写磁盘。
具体到Mysql里就是,当有一条记录需要更新的是时候,InnoDB会把记录先写到日志里,再更新内存,此时更新完成。然后当空闲的时候InnoDB引擎会将日志更新到磁盘里。除此之外,当日志文件写满的时候,InnoDB会暂时放下当前工作,将日志文件中的一部分更新到磁盘里面,然后继续执行当前工作,继续写日志。
Redo log是固定大小的,比如可以配置一组4个文件,每个文件的大小是1GB,那么就可以记录4GB的操作。从开始写,写到末尾就又回到开头循环写。如上图所示。
write pos 是当前记录的位置,一边写一边后移,写到三号文件末尾后 就回到0号文件开头。check point是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
write pos 和 check point 之间是可以记录新操作的空间,如果write pos 能追上check point 表示当前日志文件写满,不能执行新的操作,必须将日志写到磁盘中,把check point 推进一下。
有了 redo log,InnoDB就可以保证数据库发生异常重启,之前提交的记录不丢失,这个能力称之为crash-safe。
binlog(归档日志)
redo log 是 InnoDB引擎特有的日志,bin log是server层自己的日志 。
binlog和redo log主要有以下几点不同。
- redo log 是InnoDB引擎特有的,binlog是Mysql的Server层实现的,所有引擎都可以使用。
- redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给 id=2 这一行的c字段加一”
- redo log 是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
执行流程
例如下面执行语句
update T set c=c+1 where ID=2;
- 执行器先去找ID=2这一行,ID是主键,引擎直接用树搜索找到这一行。如果ID=2这一行本来就在内存中,就直接返回给执行器,否则就需要先从磁盘读入内存,然后再返回。
- 执行器拿到行数据,把这个值加一,得到新的一行数据,再调用存储引擎接口写入这行新数据
- 引擎将改行数据更新到内存中,同时将更新操作记录到redo log 里面,此时redo log 处于prepare状态,同时告知执行器执行完成了,随时可以提交事务。
- 执行器生成这个操作的binlog,并把binlog写入磁盘
- 执行器调用引擎的提交事务接口,把刚刚写的reldo log 改成提交(commit)状态,状态更新完成。
两阶段提交
我的理解是为了保证两个日志文件的一致性从而保证库恢复后的一致性。考虑下面几种情况。
- 先写redo 再写bin。假设redo log 写完,binlog还没有写完,mysql进程异常重启。此时redolog写完,系统即使崩溃依旧能将数据恢复回来,所以恢复后c的值为1.
但是binlog没写完 crash,此时不会记录该语句,因此恢复的时候这一行的值为0。 - 先写bin 再写redo。假设binlog 写完,redo log还没有写完,mysql进程异常重启。此时使用binlog恢复值为1,redolog恢复值为0.
- 使用两阶段提交时 redolog只是完成了prepare, 而binlog又失败,那么redolog 事务本身会回滚,所以这个库里面c的值是0。
1 prepare阶段 2 写binlog 3 commit
当在2之前崩溃时
重启恢复:后发现没有commit,回滚。备份恢复:没有binlog 。
一致
当在3之前崩溃
重启恢复:虽没有commit,但满足prepare和binlog完整,所以重启后会自动commit。备份:有binlog. 一致
关于脏页
脏页,干净页
当内存数据页和磁盘数据页上的内容不一致时,我们称这个内存页为脏页;
内存数据写入磁盘后,内存页上的数据和磁盘页上的数据就一致了,我们称这个内存页为干净页。
刷脏页的时机
redo log
redo log 是循环写的,当redo log 写满了,即 write pos 追上了 checkpoint 时,此时没有空间记录 redo log,就需要将 checkpoint 向前推进,推进的这部分日志对应的脏页就需要刷入磁盘。此时所有的更新全部阻塞,此时写性能跌为0,必须等待刷一部分脏页后才能继续更新,这种情况要尽量避免;
系统内存
当系统内存不足时,就需要将一部分数据页淘汰掉,如果淘汰的是脏页,就需要先将脏页刷入磁盘。
当淘汰的脏页过多时,会导致查询的响应时间变长;