@[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 会长久化到磁盘中。
具体来说,有如下几个长久化机会:
- 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 长久化的机会。
- 当 redo log buffer 的使用量达到
innodb_log_buffer_size
的一半时,将其写入磁盘成为 redo log file。 - 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…