binlog流程 mysql_MySQL事务日志Redo_Log之Crash_Safe原理和事务两阶段提交原理

MySQL的崩溃恢复能力依赖于Redo Log。更新数据时,先修改内存并写Redo Log,以提高性能。两阶段提交避免数据不一致:先写Redo Log准备阶段,再写binlog。崩溃恢复时,根据Redo Log和binlog仲裁决定提交或回滚事务。
摘要由CSDN通过智能技术生成

6c7755c341d997257bb3d3edddbc695e.png

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语句的执行流程图为:

eb0dfc0074d559bc37d53f44b0dce1d5.png

从上图我们可以看到,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

8c559e9e38e106ab934f82d5756c245d.png0b58f24e947bba3f57cc8ce5edb5e855.gifcc5eef4cc64228e51726d28b5bd0f8dc.pnga0608c1e6061ba9dc962289f1c409b82.gif想要获取学习实战、高并发、架构 、笔试面试资料请扫码咨询+薇薇微信
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值