MySQL实战 | 02-MySQL 如何恢复到半个月内任意一秒的状态?

看到这个题目是不是觉得数据库再也不用担心服务器 crash 了?

那我们需要学习为什么可以这么做?以及如何做?

即为什么可以恢复到任意时间点?如何恢复到任意时间点?

为什么有了 binlog 还需要 redo log?

事务是如何提交的?事务提交先写 binlog 还是 redo log?如何保证这两部分的日志做到顺序一致性?

为了保障主从复制安全,故障恢复是如何做的?

上一次课我们学习了一条 select 语句的全部执行过程,那么今天我们就从一条 update 语句开始。

mysql> update T set c=c+1 where ID=2;

其实执行流程和查询流程一致,只是最后执行器执行的是找到这条数据,并进行更新。

另外,更新过程还涉及到一个重要的日志模块,即 redo log(重做日志)和 binlog(归档日志)。

我个人是只听过 binlog 的。

redo log

和大多数关系型数据库一样,InnoDB 记录了对数据文件的物理更改,并保证总是日志先行

也就是所谓的 WAL(Write-Ahead Logging),即在持久化数据文件前,保证之前的 redo 日志已经写到磁盘。

MySQL 的每一次更新并没有每次都写入磁盘,InnoDB 引擎会先将记录写到 redo log 里,并更新到内存中,然后再适当的时候,再把这个记录更新到磁盘。

这里有必要贴一下 InnoDB 的存储结构图:

[InnoDB 物理存储结构][1]

如果下面看的各种空间懵逼了,建议回来看一眼这个图。

redo log 是啥

当数据库对数据做修改的时候,需要把数据页从磁盘读到 buffer pool 中,然后在 buffer pool 中进行修改,那么这个时候 buffer pool 中的数据页就与磁盘上的数据页内容不一致,我们称 buffer pool 的数据页为 dirty page 脏数据

[dirty page][2]

这里也可以看出,所有的更新操作都是现在 dirty page 中进行的。

如果这个时候发生非正常的 DB 服务重启,那么这些数据还没在内存,并没有同步到磁盘文件中(注意,同步到磁盘文件是个随机 IO),也就是会发生数据丢失

如果这个时候,能够在有一个文件,当 buffer pool 中的 dirty page 变更结束后,把相应修改记录记录到这个文件(注意,记录日志是顺序 IO),那么当 DB 服务发生 crash 的情况,恢复 DB 的时候,也可以根据这个文件的记录内容,重新应用到磁盘文件,数据保持一致。

这个文件就是 redo log ,用于记录数据修改后的记录,顺序记录。

我理解的,redo log 就是存放 dirty page 的物理空间。

log 何时产生 & 释放?

在事务开始之后就产生 redo log,redo log 的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入 redo log 文件中。

当对应事务的脏页写入到磁盘之后,redo log 的使命也就完成了,重做日志占用的空间就可以重用(被覆盖)。

如何写?

Redo log 文件以 ib_logfile[number] 命名,并以顺序的方式写入文件文件,写满时则回溯到第一个文件,进行覆盖写。

[循环写][3]

如图所示:

write pos 是当前记录的位置,一边写一边后移,写到最后一个文件末尾后就回到 0 号文件开头;

checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件;

write pos 和 checkpoint 之间还空着的部分,可以用来记录新的操作。

如果 write pos 追上 checkpoint,表示写满,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

Redo log 文件是循环写入的,在覆盖写之前,总是要保证对应的脏页已经刷到了磁盘

在非常大的负载下,Redo log 可能产生的速度非常快,导致频繁的刷脏操作,进而导致性能下降。

通常在未做 checkpoint 的日志超过文件总大小的 76% 之后,InnoDB 认为这可能是个不安全的点,会强制的 preflush 脏页,导致大量用户线程 stall 住。

如果可预期会有这样的场景,我们建议调大 redo log 文件的大小。可以做一次干净的 shutdown,然后修改 Redo log 配置,重启实例。

参考:
[][4]

相关配置

默认情况下,对应的物理文件位于数据库的 data 目录下的 ib_logfile1、ib_logfile2。

innodb_log_group_home_dir 指定日志文件组所在的路径,默认./ ,表示在数据库的数据目录下。 innodb_log_files_in_group 指定重做日志文件组中文件的数量,默认2 # 关于文件的大小和数量,由一下两个参数配置 innodb_log_file_size 重做日志文件的大小。 innodb_mirrored_log_groups 指定了日志镜像文件组的数量,默认1 其他

redo log 有一个缓存区 Innodb_log_buffer,默认大小为 8M,Innodb 存储引擎先将重做日志写入 innodb_log_buffer 中。

[写 redo log 过程][5]

然后会通过以下三种方式将 innodb 日志缓冲区的日志刷新到磁盘:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssxfw.html