redo log(InnoDB引擎特有的)

  • WAL技术,WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘
  • 当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log里面,并更新内存,这个时候更新就算完成了。
  • 同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做
  • InnoDB的redo log是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示:

image.png

  • write pos是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。
  • checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
  • 有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe

binlog(归档日志)(Server层的日志)

为什么会有两份日志呢?

  • MySQL一开始自带的引擎(存储引擎)是MyISAM,没有crash-safe的能力,binlog日志只能用于归档

两种日志有什么不同?

  1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
  2. redo log记录的是“在某个数据页上做了什么修改”;binlog记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”SQL语句。
  3. redo log是循环写的,空间固定会用完;binlog是可以追加写入,不覆盖旧的

执行器和InnoDB引擎在执行一个简单的update语句都干了些啥?

  1. create table T(ID int primary key, c int);
  2. update T set c=c+1 where ID=2;
  1. 执行器首先需要让引擎取 ID=2 这一行,由于ID是主键,使用聚簇索引(B+树)搜索找到这一行,并通过读取内存或是硬盘得到数据。
  2. 执行器根据得到的数据,把指定的值+1后得到新值,并调用引擎写入该值
  3. 引擎把数据存到内存中,同时会把该更新记录存到redo log里面,此时redo log处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。
  4. 执行器生成这个操作的binlog,并把binlog写入磁盘。
  5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交(commit)状态,更新完成。

image.png
图中浅色框表示是在InnoDB内部执行的,深色框表示是在执行器中执行的

两阶段提交

redo log的写入拆成了两个步骤:prepare和commit,这就是”两阶段提交”。

系统在崩溃后恢复时,分为以下3种情况:

  1. binlog有记录,redolog状态commit:正常完成的事务,不需要恢复;
  2. binlog有记录,redolog状态prepare:在binlog写完提交事务之前的崩溃,恢复操作:提交事务。(因为之前没有提交)
  3. binlog无记录,redolog状态prepare:在binlog写完之前的崩溃,恢复操作:回滚事务(因为crash时并没有成功写入数据库)

简单说,redo log和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

  • 先写redo log后写binlog
    • 如果在一条语句redolog之后崩溃了,binlog则没有记录这条语句。系统在crash recovery时重新执行了一遍binlog便会少了这一次的修改。恢复的数据库少了这条更新。
  • 先写binlog后写redo log
    • 如果在一条语句binlog之后崩溃了,redolog则没有记录这条语句(数据库物理层面并没有执行这条语句)。系统在crash recovery时重新执行了一遍binlog便会多了这一次的修改。恢复的数据库便多了这条更新。