wky233 的个人博客

记录精彩的程序人生

Open Source, Open Mind,
Open Sight, Open Future!
  menu
40 文章
10233 浏览
1 当前访客
ღゝ◡╹)ノ❤️

MySQL学习笔记-----日志模块

MySQL有两大重要日志模块,redo log(重做日志)和binlog(归档日志)。

重要日志模块: redo log

redo log可以理解为一个日志文件,当MySQL接收到很多更新请求时,一时处理不完(因为数据库储存数据量大,查找更新慢),就可以把请求先写入redo log,然后再慢慢写入数据库。其实就是MySQL里经常说到的WAL技术,WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘

InnoDB的redo log是固定大小的,所以就会出现写满的情况。比如可以配置为一组4个文件,每个文件的大小是1GB,那么这块“粉板”总共就可以记录4GB的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。

write pos是记录当前位置,一边写一边移动,写到第3号文件末尾后,就回到0号文件开头。而checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据库。

write pos和 checkpoint之间是还空着的部分,可以用来记录新的操作,如果write pos追上checkpoint,表示redo log满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把checkpoint推进一下。

有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe

重要的日志模块:binlog

上面我们聊到的redo log是InnoDB引擎特有的日志,而Server层也有自己的日志,称为binlog(归档日志)。

这两种日志有以下三点不同:

  1. redo log是InnoDB引擎独有的,binlog是Server层实现的,所有引擎都可以用。
  2. redo log是物理日志,记录的是“在某个数据页上做了什么修改”; binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。
  3. redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
  4. redo在 事务执行过程中 会不断的写入,而 binlog 是在 事务最终提交前 写入的。

binlog 记录的都是事务操作内容,binlog 有三种模式:Statement(基于 SQL 语句的复制)、Row(基于行的复制) 以及 Mixed(混合模式)。具体这三种模式的区别请看主从同步和主备同步专栏。

两阶段提交

  • 为什么必须有“两阶段提交”呢?这是为了让两份日志之间的逻辑一致。redolog的写入分为了两个步骤: prepare和commit。

如果不使用两阶段提交:
先写入redo再写入binlog,那么当写入redo后,数据库发生异常中断。重启后,redo log写完后,仍能够把数据恢复回来。但是binlog就没有记录这条语句,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,会导致数据不一致。

如果先写binlog再写入redo,那么在binlog写入后进行crash,由于redo还没来的及写,崩溃恢复(崩溃恢复用redo)以后这个事务无效, 单用binglog来恢复时就多了一个事务出来。

具体而言,崩溃恢复在两阶段提交不同时刻的判断规则如下:图中浅绿色在Server层,深绿色位于innodb层。

1.如果 redo log 里面的事务是完整的,也就是已经有了 commit 标识,则直接提交;

2.如果 redo log 里面的事务只有完整的 prepare ,则判断对应的事务 binlog 是否存在并完整:通过xid来联系起来。
a. 如果是,则提交事务:

如果把 innodb_flush_log_at_trx_commit 设置成 1 ,那么 redo log 在 prepare 阶段就要持久化一次,因为这个崩溃恢复逻辑是要依赖于prepare 的 redo log ,再加上 binlog 来恢复的

b. 否则,回滚事务。
时刻 A 的地方,也就是写入 redo log 处于 prepare 阶段之后、写 binlog 之前,发生了崩溃( crash ),由于此时 binlog 还没写, redo log 也还没提交,所以崩溃恢复的时候,这个事务会回滚。这时候, binlog 还没写,所以也不会传到备库。

在时刻 B ,也就是 binlog 写完, redo log 还没 commit 前发生crash ,此时崩溃对应的是2(a)的情况,崩溃恢复过程中事务还是会被提交

总结:
redo log 记录的,即使异常重启,都会刷新到磁盘,而 bin log 记录的, 则主要用于备份。

binlog 写完以后 MySQL 发生崩溃,这时候 binlog 已经写入了,之后就会被从库(或者用这个binlog 恢复出来的库)使用。 所以,在主库上也要提交这个事务。采用这个策略,主库和备库的数据就保证了一致性。

声明:此篇文章的主体内容参考自极客时间的MySQL实战45讲,非本人原创,只是在学习的过程中觉得有必要将其写入个人博客之中,且最终目的只是为了方便自己或有需要的人进行查阅。此外,若需转载本文仍需本人同意。

上一篇:MySQL学习笔记-----基础架构
下一篇: MySQL学习笔记-----事务隔离


标题:MySQL学习笔记-----日志模块
作者:wky181
地址:https://www.wkyhky.site/articles/2020/01/13/1578905369978.html