Mysql面试题系列-什么是crash-safe能力?什么是两阶段提交?

226 阅读5分钟
前言

这是我的第一篇Mysql系列的文章,接下来我将以Mysql面试题为线索,写一系列Mysql相关的文章,欢迎关注和支持,有需要的小伙伴可以先收藏再看哦~ 本文首发于微信公众号:pipi的奇思妙想

正文

Innodb引擎具有crash-safe能力,这种crash-safe 能力,是通过引擎层的redo log 来实现的。

redo log

事务在提交写入磁盘前,会先写到redo log里面去。

为什么不直接写到Mysql中去?这是因为数据写到Mysql中去,需要找到磁盘的Mysql的对应的页,涉及磁盘的随机I/O访问,涉及磁盘随机I/O访问是非常消耗时间的一个过程,相比这个时间,先写入redo log,后面再找合适的时机刷盘,能大大提升效率。

另外,如果Mysql 进程异常重启了,系统会自动去检查redo log,将未写入到Mysql的数据从redo log恢复到Mysql中去。

redo log存储的是页的物理日志,即在这个页上做了什么改动。

redo log是固定大小的一组文件,采用“循环写“的方式,如下图,redo log可以设置为一组4个文件:

在这里插入图片描述

什么是循环写呢?事务提交时,会先写到redo log里面去,当写完一个事务时,write pos会往前移动,在redo log中的记录被更新到数据库中时,checkpoint 会往前移动。

write pos和 checkpoint 之间的记录,是可以被擦除的。

当write pos 和 checkpoint 重合时,write pos会回到最开头的文件,重新开始写。

其中checkpoint 表示已经刷新到磁盘上的日志序列号,即LSN。 另外,每个页上也会记录一个LSN,用于表示已经刷新的数据。

crash-safe

redo log的存在使得数据库具有crash-safe能力,即如果Mysql 进程异常重启了,系统会自动去检查redo log,将未写入到Mysql的数据从redo log恢复到Mysql中去。

当数据库发生异常重启时,系统会自动定位到上次checkpoint的位置,同时,每个数据页中也存在一个LSN,当redo log中的LSN大于数据页中的LSN时,说明重启前redo log中的数据未完全写入数据页中,那么将从数据页中记录的LSN开始,从redo log中恢复数据。 比如redolog 的LSN 是 13000,数据库页的LSN是 10000,那么说明重启前有部分数据未完全刷入到磁盘的数据页中,那么系统将会恢复redo log 中LSN从10000开始到13000的记录到数据页中。 在这里插入图片描述 当redo log中的LSN小于数据页中的LSN时,说明数据页已经被刷到该位置,所以不需要进行恢复。

两阶段提交
Mysql Server的大体架构

Mysql大体可以分为Server层和存储引擎层,其中binlog在Server层,redo log在存储引擎层。 在这里插入图片描述

binlog简介

binlog是Mysql server层的日志,主要用于数据误删后进行数据恢复,另外,主从复制也需要依靠binlog。

过程

redolog 是Mysql InnoDB引擎层的日志,为了保证两份日志最终恢复到数据库的数据是一致的,采用两阶段提交的机制。

主要过程如下: (图) 1)执行器调用存储引擎接口,存储引擎将修改更新到内存中后,将修改操作写到redo log里面,此时redo log处于prepare状态; 2)存储引擎告知执行器执行完毕,执行器开始将操作写入到bin log中,写完后调用存储引擎的接口提交事务; 3)存储引擎将redo log的状态置为commit。

两阶段提交机制的必要性

binlog 存在于Mysql Server层中,主要用于数据恢复;当数据被误删时,可以通过上一次的全量备份数据加上某段时间的binlog将数据恢复到指定的某个时间点的数据。 redo log 存在于InnoDB 引擎中,InnoDB引擎是以插件形式引入Mysql的,redo log的引入主要是为了实现Mysql的crash-safe能力。

假设redo log和binlog分别提交,可能会造成用日志恢复出来的数据和原来数据不一致的情况。

1)假设先写redo log再写binlog,即redo log没有prepare阶段,写完直接置为commit状态,然后再写binlog。那么如果写完redo log后Mysql宕机了,重启后系统自动用redo log 恢复出来的数据就会比 binlog记录的数据多出一些数据,这就会造成磁盘上数据库数据页和binlog的不一致,下次需要用到 binlog恢复误删的数据时,就会发现恢复后的数据和原来的数据不一致。 2)假设先写binlog再写redolog。如果写完redo log后Mysql宕机了,那么binlog上的记录就会比磁盘上数据页的记录多出一些数据出来,下次用binlog恢复数据,就会发现恢复后的数据和原来的数据不一致。

由此可见,redo log和binlog的两阶段提交是非常必要的。

这篇文章就讲到这里,如有错漏,欢迎批评指正~

你的点赞/喜欢/收藏/分享都是我更文的最大动力~

更多精彩内容,尽在微信公众号:pipi的奇思妙想

巨人的肩膀(参考资料):

丁奇《Mysql实战45讲》

书籍《Mysql技术内幕:InnoDB存储引擎》