likes
comments
collection
share

MySQL是如何保证持久性的?

作者站长头像
站长
· 阅读数 44

MySQL是如何保证持久性的?

一、什么是事务的持久性?

当现实世界的一个状态转换完成后,这个转换的结果将永久的保留,这就称为持久性。

二、MySQL是如何实现事务的持久性?

先说结论

具体的手段就是通过redo日志来实现。

下边的文字想看就看,不看也没关系啦~ 每条redo日志的结构差不多记载了发生变更的数据在哪儿(哪个表空间、哪个页号,哪个字节处开始),做了哪些变更。由于日志直接就指向了发生变更的物理地址,所以redo log其实也是个物理日志。


MySQL持久性问题背景

先介绍下现在的情况~

MySQL是如何保证持久性的?

可以看到途中有三个箭头连线,我们看上面两个。

当用户读写数据时,直接访问到的数据其实是内存中的数据,更准确得说,是一块叫做Buffer Pool的内存,而Buffer Pool的数据又来自磁盘。

图中可以看到数据页,其实可以叫页。所谓页,就是一个大小为16kb的内存空间。 我们的内存空间有限,总不能把所有磁盘数据加载到内存里吧,这么整地球都得爆炸!那只加载部分数据,也不能没个章法,所以定义一个“页”的概念,磁盘中的数据就可以被切分成好多页,每页16kb,然后再以页为最小单位,加载若干页到内存,这样数据库的各种管理是不是就很方便了,几乎很多操作就是以页为单位在进行的。

那么问题来了……

既然数据的源头是磁盘,为什么不直接访问磁盘?因为磁盘I/O实在不给力——慢死你,所以MySQL的设计中专门向操作系统申请了一块内存,并起名为Buffer Pool。

在这样的前提之下,用户直接操作的必然内存中的数据,这样肯定不算完:因为我们还没把这些数据刷入磁盘,此时伸出邪恶的小手,轻轻给你把电源插头,你不得吱哇乱叫:数据全特喵没了!

日常反思,可以跳过哈!

所以啊有时候解决一个单一的问题是很简单的,但是当多个问题揉在一起,一个问题的解决方案可能会为另一个问题的解决设置障碍,所以多个问题各自解决方案的组合也很重要,因为不恰当的解决优先级和针对前置问题的不当解决方案,可能会让后续问题的解决陷入僵局。拆分问题,打开思路,回过头来再思考,不要走进死胡同,自勉自省!

那……试试立刻刷盘?

按照我朴素的直觉,我肯定要支招了:那还等什么,赶紧刷盘!嗨~这想法蠢蠢的,怪可爱的啊……为啥?因为I/O很慢,要是能赶紧得起来,也就不会有Buffer Pool的设计啦!

三、怎么破?救世主降临——redo log

让我这破锣一样的脑袋想,我是想到下辈子也想不粗来,还好MySQL的大佬们各个身怀绝技,这点问题不在话下,大佬们引入了redo log,专治各种不服。

redo log见文知意

至于redo log这个词儿 ,可难不倒我这个英语六级、张嘴就哑火的chglish杰出用户嘛!这不就是重做日志?“望文生义”一下:就是系统崩溃后,我可以根据重做日志(redo log),把崩溃期间没刷盘的数据变更再做一遍,不就……超完美的好嘛!当然,redo log的功能确实也是如此,并不是我胡说八道哈——看来一个好的名字是可以让知识更加顺利地进入脑袋瓜里的!

客户端发起写操作后,redo log 是如何参与进去的?

MySQL是如何保证持久性的?

上面的图罗列了当客户端发起写操作后,数据库的4个举动:

  1. 修改数据页

这个时候就产生了脏页了,脏页也就是用户操作后发生变更的数据页。

  1. 修改redo log block

就是增加重做日志啦,这个是我们讨论持久性的重点关注对象。至于block,咱们只要知道block的含义其实和“页”是一样的就行,其他不用深究。

  1. 将redo log刷入磁盘
  2. 将脏页刷回磁盘

redo log 刷盘必须一马当先

注意哟,这几个动作先后顺序很重要,尤其是step3和4,只有保证3在4之前执行,通过redo log做崩溃恢复时,数据才是一致和准确的。此话怎讲?我们来穷举下崩溃的场景:

  1. 如果redo log刷盘失败,脏页刷盘还没执行到,系统崩溃后重启,会根据redo log恢复,很显然是没问题的:数据相当于什么修改都没发生过。
  2. 如果redo log成功,之后某个时间点系统崩溃,导致脏页数据刷盘失败,那么系统重启后就可以根据redo log 把缺失的这部分数据差异给补上啦。

四、最后的碎碎念

其实说到这里,关于MySQL是如何通过redo log保证事务四大特性的持久性的,也已经写得差不多了,欢迎大家指正和建议!

转载自:https://juejin.cn/post/7328244694734929931
评论
请登录