binlog和redoLog在崩溃恢复上的作用
what:
崩溃恢复:即使在数据库宕机的情况下,也不会出现操作一半的情况;
bin log :是server层的归档日志,不足以实现崩溃恢复(crash-safe);
redo log :是物理日志,具有崩溃恢复的能力;
diff:
1、适用对象:
bin log: 是 MySQL 的 Server 层实现的,所有引擎都可以使用;
redo log :是 InnoDB 引擎特有的;
2、写入内容:
bin log:是逻辑日志。记录的是这个语句的原始逻辑,比如 “给 id = 1 这一行的 age 字段加 1”;
redo log :是物理日志。记录的是 “在某个数据页上做了什么修改”;
3、写入方式:
bin log:是追加写入。“追加写” 是指 bin log 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。那么就会出现“没有标志能让 InnoDB 从 bin log 中判断哪些数据已经刷入磁盘了,哪些数据还没有”;
redo log :是循环写入。即空间固定会被用完;那么“只会记录未刷入磁盘的日志,已经刷入磁盘的数据就会删掉”;
how:
核心方案:redo log采用两阶段提交。即redo log的写入拆分为了2个步骤:prepare和commit;
SQL 查询语句的执行过程:(具体流程入下图)
1、MySQL 客户端与服务器间建立连接,客户端发送一条查询给服务器;
2、服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果;否则进入下一阶段;
3、服务器端进行 SQL 解析、预处理,生成合法的解析树;
4、由优化器生成对应的执行计划;
5、执行器根据执行计划(优化器生成),调用相应的存储引擎的 API 来执行,并将执行结果返回给客户端;
SQL更新语句的执行过程:相对查询多了,两日志模块 bin log 和 redo log的操作。
以“update tablese tage=age+1 where id=1;”为栗子:
注意:以下操作和查询的前4步相同。
1、执行器:找存储引擎取到 id = 1 这一行记录;
2、存储引擎:根据主键索引树找到这一行,如果 id = 1 这一行所在的数据页本来就在内存池(Buffer Pool)中,就直接返回给执行器;否则,需要先从磁盘读入内存池,然后再返回;
3、执行器:拿到存储引擎返回的行记录,把 age 字段加上 1,得到一行新的记录,然后再调用存储引擎的接口写入这行新记录;
4、存储引擎:将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare
状态。然后告知执行器执行完成了,随时可以提交事务;
注意:此处的“事务”是提交过程中的一个小步骤,也是最后一步,而非 sql 语句中的提交事务 commit 命令
5、执行器:生成这个操作的 bin log,并把 bin log 写入磁盘;
6、执行器:调用存储引擎的提交事务接口;
7、存储引擎:把刚刚写入的 redo log 状态改成提交(commit
)状态,更新完成;
具体如下图:
why():
怎么判断bin log 是不是完整的?
1、statement 格式的 bin log,最后会有 COMMIT;
2、row 格式的 bin log,最后会有 XID event;
3、对于 bin log 可能会在中间出错的情况,MySQL 5.6.2 版本以后引入了 binlog-checksum
参数,用来验证 bin log 内容的正确性;
为何redo log有崩溃恢复能力?
1、如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交;
2、如果 redo log 里面的事务处于 prepare 状态,则判断对应的事务 binlog 是否存在并完整
a、如果 binlog 存在并完整,则提交事务;
b、否则,回滚事务;
栗子1:“数据库在写入 redo log(prepare) 阶段之后、写入 binlog 之前,发生了崩溃”。
分析:此时,redo log处于prepare状态,但是binlog没有完成,事务就需要回归。
原因:binlog 还没有写入,之后从库进行同步的时候,就会缺少数据,但是主库中已经有数据了,结果就是“主从不一致”,所以主库的操作需要回滚。
栗子2:“数据库在写入 binlog 之后,redo log在commit之前发生了崩溃”。图如下:
分析:redo log处于prepare状态,binlog完整了,事务直接提交。
原因: binlog 写入成功,从库能够同步过去。此时主库并没有完成这个操作,所以主备就不一致了。那么在主库上需要提交这个事务。