redo log详解

前言

不知道大家没有想过mysql是如何保证事务里的数据不丢失的?没错,就是通过redo log(下文简称redo)。

注意,绝对的数据不丢失是做不到的。我们所谈论的redo log,是针对事务而言。我们只要能保证事务中的数据不丢就行,说简单点就是:redo保证了事务的原子性和持久性。

简单解释下:

原子性:要么都做了,要么都没做。不要只做一半。比如两个人互相转账,不允许出现一个人转了,而另一个人没收到钱的情况。也就是两条update要么全部执行,要么都不执行。

持久性:数据写到磁盘了。当然这个说法不严谨,比如硬盘坏了呢?为了好理解,我就这样写了!

redo是什么?

首先明确,redo是InnoDB引擎特有的。记录着事务里对数据的修改

在mysql中,如果修改了数据,那么事务提交前,首先会被记录成redo日志写入磁盘,等到事务提交时,再把新数据写入磁盘(你以为真的是这样)。

这也就是经常说的WAL(Write-Ahead Logging)。

redo的好处

那么为什么需要redo呢?

1.保证数据的持久性。众所周知,数据是记录在磁盘上的,如果事务提交后mysql突然挂了(比如断电之类的),那么内存里的数据,是不是就丢失了?我们数据恢复时候,通过redo 就可以恢复回来。

解释:因为我们在事务提交前都已经把相关日志写入了磁盘,所以碰到意外当然可以恢复。如果写redo的时候断电了呢?大致上可以认为事务回滚了。不过没这么简单,到底是回滚还是提交,还牵扯到bin log。我们下文会讲到。

2.redo只是记录了对数据的修改,数据会比一页数据小得多。大大减少了IO频率。

解释:显而易见吧,一条redo再怎么也不会有16k那么大吧!

当然,写redo并不是一条条写的。因为一条redo日志并不是写入的最小单位,一般来说至少都是几条一起写。这是因为一条修改语句对B+树的修改,绝大多数情况下都不会是只产生一个修改点,比如你要插入一条数据,叶子节点容不下了,那么就可能页分裂,同时还会更新许多内节点的信息。所以这一系列对底层B+树的操作,都会以一组的形式去写入磁盘。

具体的写入过程下文会讲。现在只需要知道,一个事务会包含许多SQL,而一条SQL修改语句,会产生很多组redo就行了,而这一组(学名:Mini-Transaction)才是写入的最小单元。

好奇的你可能又会问:那这一组也没法保证写入的原子性啊,写一半断电了怎么办呢?

是的,写入永远没法保证原子性,所以只能在读取的时候保证了。在一组redo日志里,结尾会有一个标志符。解析redo日志的时候,读不到这个标志符的话,这一组就不解析了。不过这个Mini-Transaction并不是为了保证事务,我个人觉得是为了保证那颗B+树不会被搞坏了。

3.redo日志的写入是顺序IO。而修改磁盘的B+树是随机IO。

解释:redo就是往一块硬盘的某个相邻的区域写就完事了。如果要直接去修改B+树,很可能这些页并不相邻,寻址会很慢的。当然,固态硬盘的随机IO会好很多。

小白疑问:

内存里有什么数据?

答:

众所周知,InnoDB磁盘上的一页大小是16k。我们操作数据时,都是先将磁盘上的某一页读到内存中,这块内存就叫Buffer Pool。它是连续的内存空间。

这个Buffer Pool,会缓存一些热点数据、磁盘预读之类的数据。这样,操作数据时,就不用每次都去磁盘读取了。调节了CPU和硬盘的读写速度不一致的矛盾。

Buffer Pool中的数据被修改后,但又没有刷到磁盘的话(这里指的是那颗B+树),就叫做脏页。脏页不会立即刷新到磁盘中。

redo写入磁盘全流程

1.将上文提到的一组redo log写入redo log buffer(依然在内存中,依旧是为了调节CPU与磁盘写入速度的矛盾)。

2.redo log buffer写入page cache(操作系统里的页,操作系统会找个时间自动刷到磁盘。或者你调用fsync函数就能确保刷盘)。

3.page cache的数据刷到磁盘。

上述第2,3步是我们可以控制的,通过设置innodb_flush_log_at_trx_commit的值就可以控制,该变量可选值如下:(跟redis的差不多)

1:每次都要严格落盘。会调用fsync,保证了数据落盘,但是性能较差。

2:redo log buffer的数据写入page cache就行了。这个时候如果mysql挂了但是操作系统没挂,是可以等待后续落盘的。

0:不立即写入page cache。交给后台线程处理(1s一次,不仅写入page cache还会调用fsync)。这种情况太危险,但是性能最好。

怎么选就看你自己了,一般比较重要的库就设为“双一”(还有一个是binlog里的sync_binlog)。

至此redo 落盘了,从数据恢复上来讲,是可以安心了。

但是还有问题:磁盘上的redo file空间是有限的。写满了怎么办?

有人会觉得这种概率很小,其实不是的,redo log的空间重用是很正常的。那么何时才能重用呢?或者说,我们能重用哪些空间呢?

下面一一解答:

1.何时才能重用redo空间呢?

回忆redo log的作用:记录对数据的更改。那么只要Buffer Pool里的脏页也被写入磁盘了,这些磁盘上的redo log就没意义了,可以重用。

2.我们能重用哪些空间呢?

checkpoint告诉了我们答案。

checkpoint

我个人认为这是一个名词,而不是动词。

在MySQL8.0官方文档里对checkpoint的定义如下:

=============================================

checkpoint

As changes are made to data pages that are cached in the buffer pool, those changes are written to the data files sometime later, a process known as flushing. The checkpoint is a record of the latest changes (represented by an LSN value) that have been successfully written to the data files.

=============================================

我只翻译最后一段话:

checkpoint是redolog里最新的改变。

看起来有些不通顺,没关系,我加上自己的理解再翻译一次(个人理解哈,与其他资料都不太一样):

checkpoint是一个过程。当负责刷脏页的后台线程刷不动了(此时磁盘上的redo日志文件被写满了),就需要用户线程帮忙标记下,看看哪些redo日志可以被覆盖。

具体来说,redo文件里有一个偏移量(学名叫checkpoint_lsn),偏移量小于此值的redo日志可以被覆盖。当后台线程刷不动的时候,就意味着文件已经写到了上次checkpoint_lsn标记的地方。此时用户线程需要去写入日志文件里checkpoint_lsn的值。改完后后台线程就可以继续刷刷刷了。

总结:因为redo写满了,需要用户线程去写入chechpoint_lsn值的过程就是checkpoint

============================================

其实谈到checkpoint是离不开LSN(log sequence number)。

LSN这个值是干嘛的呢?其实就是记录redo在log buffer里的位置的。我们往log buffer里写入数据,比如写了10字节的数据,那么LSN = 8704+12(头大小)+10。我们12是头的大小,当然还有体和尾,大致是这么算的,就不展开了。总而言之,你往log buffer写了多少字节的日志,LSN大致就会增大多少。

Buffer Pool里的脏页们,是一个链表结构。第一次被修改的页,会以头插法的形式插入到表头,每个脏页都记录着第一次对该页修改的LSN和最后一次对该页修改的LSN(显然一个页有很多数据,可能会被修改多次的)。如果不是第一次被修改,只需要修改脏页最后一次被修改的LSN即可。

你可能会问。为什么脏页被移到链表上时,还需要记录最早和最新的LSN?

因为是头插法,尾部的是最被修改的脏页,假设叫A。那么A的最小LSN就可以作为一个分水岭,小于该值的redo 日志就可以被覆盖了。当然这个最小值也是往磁盘中写入的checkpoint值。

你又可能想问,那记录最大的LSN干嘛呢?

其实是恢复的时候有用。暂时不展开,有人看记得留言让我回来补充下。

redo什么时候写入磁盘

1.后台线程刷刷刷。

2.后台线程刷不动了(其实就是磁盘日志写满了),用户线程就会去写入checkpoint的值。使得部分redo文件可以被重写。

3.事务提交时。脏页可以不写,但是redo log在提交前必须写!

4.log bugger空间不足。

5.正常关闭服务器。

等等等等。。。

redo log与binlog

我们其实只讲了事务提交时的冰山一角。

因为mysql提交时,是采取了两段提交协议的:

1.redo log 处于prepare阶段,日志写入到磁盘。

2.写入binlog。

3.提交事务。

我们刚刚讲了那么多,其实都是描写第1步而已。其实如果只是以恢复日志来说的话,redo log完全可以胜任。

那么中间插个binlog干嘛呢?其实我不知道。连某客时间的丁某都支支吾吾,吾等实在悟不出来。暂时写这么多吧。

  • 14
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值