乐趣区

关于mysql:MySQL-为什么需要-redo-log

@[toc]
明天想和大家聊一聊 MySQL 中的 redo log,其实最早我是想聊两阶段提交的,起初想想可能有小伙伴还不理解 binlog,所以就先整了一篇 binlog:

  • 手把手教你玩 MySQL 删库不跑路,间接把 MySQL 的 binlog 玩溜!
  • MySQL 删库不跑路(视频版)

binlog 大家懂了之后,接下来还差个 redo log,redo log 大家也懂了,那么再讲两阶段提交置信小伙伴们就很容易懂了,咱们一步一步来。

1. 谁的 redo log

学习 redo log,我感觉首先要搞明确一个问题,就是是谁的 redo log?

咱们晓得,MySQL 架构整体上分为两层:Server 层和存储引擎层,如下图:

后面松哥文章 + 视频跟大家聊的 binlog,是 MySQL 本人提供的 binlog,而 redo log 则不是 MySQL 提供的,而是存储引擎 InnoDB 本人提供的。所以在 MySQL 中就存在两类日志 binlog 和 redo log,存在两类日志既有历史起因(InnoDB 最早不是 MySQL 官网存储引擎)也有技术起因,这个咱们当前再细聊。

先把这个问题搞清楚,前面很多中央就容易懂了。

2. buffer pool

在正式介绍 redo log 之前,还有一个 buffer pool 须要大家理解。

小伙伴们晓得,InnoDB 引擎存储数据的时候,是以页为单位的,每个数据页的大小默认是 16KB,咱们能够通过如下命令来查看页的大小:

16384/1024=16

刚好是 16KB。

计算机在存储数据的时候,最小存储单元是扇区,一个扇区的大小是 512 字节,而文件系统(例如 XFS/EXT4)最小单元是块,一个块的大小是 4KB,也就是四个块组成一个 InnoDB 中的页。咱们在 MySQL 中针对数据库的增删改查操作,都是操作数据页,说白了,就是操作磁盘。

然而大家想想,如果每一次操作都操作磁盘,那么就会产生海量的磁盘 IO 操作,如果是传统的机械硬盘,还会波及到很多随机 IO 操作,效率低的令人发指。这重大影响了 MySQL 的性能。

为了解决这一问题,MySQL 引入了 buffer pool,也就是咱们常说的缓冲池。

buffer pool 的次要作用就是缓存索引和表数据,以防止每一次操作都要进行磁盘 IO,通过 buffer pool 能够进步数据的访问速度。

通过如下命令能够查看 buffer pool 的默认大小:

134217728/1024/1024=128

默认大小是 128MB,因为松哥这里的 MySQL 是装置在 Docker 中,所以这个调配的小一些。一般来说,如果一个服务器只是运行了一个 MySQL 服务,咱们能够设置 buffer pool 的大小为服务器内存大小的 75%~80%。

3. change buffer

在正式介绍 redo log 之前,还有一个 change buffer 须要大家理解。

后面咱们说的 buffer pool 尽管进步了访问速度,然而增删改的效率并没有因而晋升,当波及到增删改的时候,还是须要磁盘 IO,那么效率一样低的令人发指。

为了解决这个问题,MySQL 中引入了 change buffer。change buffer 以前并不叫这个名字,以前叫 insert buffer,即只针对 insert 操作无效,当初改名叫 change buffer 了,不仅仅针对 insert 无效,对 delete 和 update 操作也是无效的,change buffer 次要是对非惟一的索引无效,如果字段是唯一性索引,那么更新的时候要去查看唯一性,仍然无奈防止磁盘 IO。

change buffer 就是说,当咱们须要更改数据库中的数据的时候,咱们把更改记录到内存中,等到未来数据被读取的时候,再将内存中的数据 merge 到 buffer pool 而后返回,此时 buffer pool 中的数据和磁盘中的数据就会有差别,有差别的数据咱们称之为脏页,在满足条件的时候(redo log 写满了、内存写满了、其余闲暇时候),InnoDB 会把脏页刷新回磁盘。这种形式能够无效升高写操作的磁盘 IO,晋升数据库的性能。

通过如下命令咱们能够查看 change buffer 的大小以及哪些操作会波及到 change buffer:

  • innodb_change_buffer_max_size:这个配置示意 change buffer 的大小占整个缓冲池的比例,默认值是 25%,最大值是 50%
  • innodb_change_buffering:这个操作示意哪些写操作会用到 change buffer,默认的 all 示意所有写操作,咱们也能够本人设置为 none/inserts/deletes/changes/purges 等。

不过 change buffer 和 buffer pool 都波及到内存操作,数据不能长久化,那么,当存在脏页的时候,MySQL 如果忽然挂了,就有可能造成数据失落(因为内存中的数据还没写到磁盘上),然而咱们在理论应用 MySQL 的时候,其实并不会有这个问题,那么问题是怎么解决的?那就得靠 redo log 了。

4. redo log 的诞生

在正式介绍 redo log 之前,还须要给大家遍及一个概念:WAL。

WAL 全称是 Write-Ahead Logging 中文译作预写日志。啥意思呢?就是说 MySQL 的写操作并不是立即更新到磁盘上,而是先记录在日志上,而后在适合的工夫再更新到磁盘上,这样的益处是错开高峰期的磁盘 IO,进步 MySQL 的性能。

配合上后面的 buffer pool 和 change buffer,WAL 就是说在操作 buffer pool 和 change buffer 之前,会先把记录写到 redo log 日志中,而后再去更新 buffer pool 或者 change buffer,这样,即便零碎忽然崩了,未来也能够通过 redo log 复原数据。当然,redo log 自身又分为:

  • 日志缓冲(redo log buffer),该局部日志是易失性的。
  • 重做日志 (redo log file),这是磁盘上的日志文件,该局部日志是长久的。

那有人说,写 redo log 不就是磁盘 IO 吗?而写数据到磁盘也是磁盘 IO,既然都是磁盘 IO,那干嘛不把间接把数据写到磁盘呢?还费这事!

此言差矣。

写 redo log 跟写数据有一个很大的差别,那就是 redo log 是程序 IO,而写数据波及到随机 IO,写数据须要寻址,找到对应的地位,而后更新 / 增加 / 删除,而写 redo log 则是在一个固定的地位循环写入,是程序 IO,所以速度要高于写数据。

如前文所说,redo log 波及到两个货色:redo log buffer 和 redo log file,这两个货色咱们别离来介绍。

4.1 redo log buffer

先来说 redo log buffer。

咱们说数据的变动先写入 redo log 中,并不是上来就写磁盘,也是先写到内存中,即 redo log buffer,在时机成熟时,再写入磁盘,也就是 redo log file。

咱们先来看看 redo log buffer 有多大:

16777216 ÷ 1024 ÷ 1024 = 16MB

能够看到,这个 redo log buffer 大小刚好是 16MB,如果你感觉这个值有点小,也能够自行批改其大小。

数据的变更都会首先记录在这块内存中。小伙伴们晓得,MySQL 的增删改,如果咱们没有显式的开启事务,MySQL 外部也是有一个事务存在的,当外部这个事务 commit 的时候,redo log buffer 会长久化到磁盘中。

具体来说,有如下几个长久化机会:

  1. innodb_flush_log_at_trx_commit

通过 innodb_flush_log_at_trx_commit 参数来管制长久化机会,该参数默认值为 1,如下图:

当然开发者可依据本人的理论需要批改该参数。该参数有三种取值,含意别离如下:

  • 0:每秒一次,将 redo log buffer 中的数据刷新到磁盘中。
  • 1:每次 commit 时,将 redo log buffer 中的数据刷新到磁盘中,即只有 commit 胜利,磁盘上就有对应的 redo log 日志, 这是最平安的状况,也是举荐应用的参数
  • 2:每次 commit 时,将 redo log buffer 中的数据刷新到操作系统缓存中,操作系统缓存中的数据每秒刷新一次,会长久化到磁盘中。

这是第一种 redo log buffer 长久化的机会。

  1. 当 redo log buffer 的使用量达到 innodb_log_buffer_size 的一半时,将其写入磁盘成为 redo log file。
  2. MySQL 敞开时,将 redo log buffer 写入磁盘成为 redo log file。

那如果 redo log buffer 中的数据还没有磁盘,MySQL 就挂了该怎么办?没写入磁盘,阐明你还没 commit,既然没 commit,那就数据批改操作都还没有实现,那只能丢了就丢了,如果曾经 commit 了,那么数据就会长久化到 redo log file 中,此时即便 MySQL 挂了,未来 MySQL 重启复原了,数据也是能够被复原的。具体的复原逻辑,就波及到两阶段提交了,这个松哥在前面的文章中再和大家具体介绍。

4.2 redo log 落盘

还有一个须要大家留神的问题就是 redo log 落盘,落盘的数据从哪里来?是从 redo log 日志中来还是从 buffer pool 中来?

在后面的文章中咱们说过:binlog 是一种逻辑日志,他里边所记录的是一条 SQL 语句的原始逻辑,例如给某一个字段 +1,这区别于 redo log 的物理日志,物理日志记录的是在某个数据页上做了什么批改。

因为 redo log 并没有记录数据页的残缺数据,所以失常的落盘其实用不到 redo log,数据落盘的机会到了时,间接拿着将脏页(buffer pool)长久化到磁盘中即可。

好啦,明天就和大家分享这么多,redo log 还有一些内容,咱们在前面的文章中再持续聊~

参考资料:

  • https://www.cnblogs.com/ZhuCh…
退出移动版