redo log(InnoDB引擎特有的)
- WAL技术,WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘
- 当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到
redo log
里面,并更新内存,这个时候更新就算完成了。 - 同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做
- InnoDB的
redo log
是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示:
write pos
是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint
是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。- 有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。
binlog(归档日志)(Server层的日志)
为什么会有两份日志呢?
- MySQL一开始自带的引擎(存储引擎)是MyISAM,没有crash-safe的能力,binlog日志只能用于归档
两种日志有什么不同?
- redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
- redo log记录的是“在某个数据页上做了什么修改”;binlog记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”SQL语句。
- redo log是循环写的,空间固定会用完;binlog是可以追加写入,不覆盖旧的
执行器和InnoDB引擎在执行一个简单的update语句都干了些啥?
create table T(ID int primary key, c int);
update T set c=c+1 where ID=2;
- 执行器首先需要让引擎取 ID=2 这一行,由于ID是主键,使用聚簇索引(B+树)搜索找到这一行,并通过读取内存或是硬盘得到数据。
- 执行器根据得到的数据,把指定的值+1后得到新值,并调用引擎写入该值
- 引擎把数据存到内存中,同时会把该更新记录存到
redo log
里面,此时redo log
处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。 - 执行器生成这个操作的binlog,并把binlog写入磁盘。
- 执行器调用引擎的提交事务接口,引擎把刚刚写入的
redo log
改成提交(commit)状态,更新完成。
图中浅色框表示是在InnoDB内部执行的,深色框表示是在执行器中执行的
两阶段提交
redo log
的写入拆成了两个步骤:prepare和commit,这就是”两阶段提交”。
系统在崩溃后恢复时,分为以下3种情况:
- binlog有记录,redolog状态commit:正常完成的事务,不需要恢复;
- binlog有记录,redolog状态prepare:在binlog写完提交事务之前的崩溃,恢复操作:提交事务。(因为之前没有提交)
- binlog无记录,redolog状态prepare:在binlog写完之前的崩溃,恢复操作:回滚事务(因为crash时并没有成功写入数据库)
简单说,redo log和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。
- 先写redo log后写binlog
- 如果在一条语句redolog之后崩溃了,binlog则没有记录这条语句。系统在crash recovery时重新执行了一遍binlog便会少了这一次的修改。恢复的数据库少了这条更新。
- 先写binlog后写redo log
- 如果在一条语句binlog之后崩溃了,redolog则没有记录这条语句(数据库物理层面并没有执行这条语句)。系统在crash recovery时重新执行了一遍binlog便会多了这一次的修改。恢复的数据库便多了这条更新。