MySQL事务日志Redo_Log之Crash_Safe原理和事务两阶段提交原理
Posted 架构师学习路线
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL事务日志Redo_Log之Crash_Safe原理和事务两阶段提交原理相关的知识,希望对你有一定的参考价值。
mysql的崩溃恢复crash_safe能力依赖于Redo Log事务日志。当MySQL更改数据的时候,它的设计思想是先对内存中的数据进行修改,并且写Redo Log,即更改数据,总是遵循WAL日志先行机制。
问题:为什么不直接更改磁盘中的数据,而是要在内存中修改,并且写Redo Log日志,最后再落盘这么复杂呢?
其实要回答这个问题并不难。MySQL更新数据的时候,之所以不直接写磁盘,最主要的就是性能问题。因为直接写磁盘是随机写,开销大性能差,所以才会设计成现在内存中对数据进行更改,后续再落盘。但是内存并不总是可靠的,万一MySQL进程挂了或者操作系统崩溃,buffer_pool中的数据也就丢失了,而这些数据还没有落盘。所以就引入了Redo Log,通过先写日志,当发生了断点重启之后,可以通过重放Redo Log来达到恢复数据。
当然,写Redo Log本质上也是写磁盘文件,Redo Log是物理日志,记录的是“某个数据页做了什么修改”。写Redo Log是顺序写,相比在直接写磁盘数据,找到不同的数据页对数据进行更新这种随机写,性能要好很多。
那么我们来看看,当MySQL更新数据的时候,其内部流程是怎么实现的呢?
假设我要执行一条SQL:update T set c=c+1 where ID=2,那么内部执行流程为:
1.执行器找存储引擎取出ID=2这一行,如果ID=2这一行记录所在的数据页本身就在内存当中,那么就直接返回给执行器;否则需要从磁盘读取到内存当中,然后再返回给执行器;
2.执行器拿到行数据之后,会对内存中的数据页进行修改,同时将这个更新操作记录到Redo Log。此时Redo Log处于perpare状态,然后告知执行器已经完成了,可以随时提交事务;
3.接下来执行器会生成这个更新操作的binlog;
4.执行器调用存储引擎的提交事务的接口,将刚刚写入的Redo Log改成commit状态;
Update语句的执行流程图为:
从上图我们可以看到,Redo Log写入之后,分成了两个阶段,分别是prepare阶段和commit阶段,这里其实就是MySQL事务的两阶段提交。
为什么需要两阶段提交呢?我们假设Redo Log不需要两阶段提交,要么就是先写完Redo Log,再写binlog,要么就是先写完binlog再写Redo Log。
1、假设是先写Redo Log,后写binlog。如果这个时候MySQL发生了进程的异常重启,由于Redo Log已经写完,MySQL崩溃之后通过crash_safe能力,能够把数据恢复回来。但是由于binlog还没写完就crash了,所以binlog里面并没有记录该SQL语句,所以使用binlog回档数据的时候,恢复出来的数据其实是少了一次更新操作的,这样就造成了灾难恢复出来的库和原库数据不一致;
2、假设是先写binlog,后写Redo Log。Binlog写完之后发生了crash,由于Redo Log还没有写,崩溃恢复之后这个事务的更新是无效的。但是binlog里面记录了这条更新的语句,所以使用binlog回档的时候就多了一条事务的更新。造成回档出来的数据和原库的数据不一致。
上图我标注了红色的“1”、“2”、“3”,分别代表的是Redo Log的prepare阶段、生成binlog阶段、以及事务提交阶段。
当MySQL在“1”,即Redo Log prepare阶段的时候发生了crash,结合binlog记录来做仲裁,由于binlog还没有写入,所以crash_safe的时候,该事务会被回滚;
当MySQL在“1”和“2”之间发生了crash,binlog还没有写入,同样事务会回滚;
当MySQL在“2”,即写完binlog之后发生了crash,结合binlog记录做仲裁,满足Redo Log prepare状态和binlog记录的完整性,crash_safe的时候会自动commit事务;
当MySQL在“2”和“3”之间发生了crash,结合binlog记录做仲裁,同样crash_safe的时候该事务会自动提交。
其实当我们开启一个事务,如:
begin;
xxxx
commit;
执行了commit指令之后,会写入binlog,以及将Redo Log的状态改成commit状态。
那么两阶段提交就是:
prepare阶段,写redo log;
commit阶段,写binlog并且将redo log的状态改成commit状态;
mysql发生崩溃恢复的过程中,会根据redo log日志,结合binlog记录来做仲裁:
如果redo log和binlog都存在,逻辑上一致,那么提交事务;
如果redo log存在而binlog不存在,逻辑上不一致,那么回滚事务;
原文:http://blog.sina.com.cn/s/blog_a1e9c7910102z8yc.html
想要获取学习实战、高并发、架构 、笔试面试资料 请扫码咨询+薇薇微信
以上是关于MySQL事务日志Redo_Log之Crash_Safe原理和事务两阶段提交原理的主要内容,如果未能解决你的问题,请参考以下文章