今天想和大家聊一聊MySQL中的redolog,其实最早我是想聊两阶段提交的,后来想想可能有小伙伴还不了解binlog,所以就先整了一篇binlog:
手把手教你玩MySQL删库不跑路,直接把MySQL的binlog玩溜!MySQL删库不跑路(视频版)binlog大家懂了之后,接下来还差个redolog,redolog大家也懂了,那么再讲两阶段提交相信小伙伴们就很容易懂了,咱们一步一步来。
1.谁的redolog学习redolog,我觉得首先要搞明白一个问题,就是是谁的redolog?
我们知道,MySQL架构整体上分为两层:Server层和存储引擎层,如下图:
前面松哥文章+视频跟大家聊的binlog,是MySQL自己提供的binlog,而redolog则不是MySQL提供的,而是存储引擎InnoDB自己提供的。所以在MySQL中就存在两类日志binlog和redolog,存在两类日志既有历史原因(InnoDB最早不是MySQL官方存储引擎)也有技术原因,这个咱们以后再细聊。
先把这个问题搞清楚,后面很多地方就容易懂了。
2.bufferpool在正式介绍redolog之前,还有一个bufferpool需要大家了解。
小伙伴们知道,InnoDB引擎存储数据的时候,是以页为单位的,每个数据页的大小默认是16KB,我们可以通过如下命令来查看页的大小:
/=16
刚好是16KB。
计算机在存储数据的时候,最小存储单元是扇区,一个扇区的大小是字节,而文件系统(例如XFS/EXT4)最小单元是块,一个块的大小是4KB,也就是四个块组成一个InnoDB中的页。我们在MySQL中针对数据库的增删改查操作,都是操作数据页,说白了,就是操作磁盘。
但是大家想想,如果每一次操作都操作磁盘,那么就会产生海量的磁盘IO操作,如果是传统的机械硬盘,还会涉及到很多随机IO操作,效率低的令人发指。这严重影响了MySQL的性能。
为了解决这一问题,MySQL引入了bufferpool,也就是我们常说的缓冲池。
bufferpool的主要作用就是缓存索引和表数据,以避免每一次操作都要进行磁盘IO,通过bufferpool可以提高数据的访问速度。
通过如下命令可以查看bufferpool的默认大小:
//=
默认大小是MB,因为松哥这里的MySQL是安装在Docker中,所以这个分配的小一些。一般来说,如果一个服务器只是运行了一个MySQL服务,我们可以设置bufferpool的大小为服务器内存大小的75%~80%。
3.changebuffer在正式介绍redolog之前,还有一个changebuffer需要大家了解。
前面我们说的bufferpool虽然提高了访问速度,但是增删改的效率并没有因此提升,当涉及到增删改的时候,还是需要磁盘IO,那么效率一样低的令人发指。
为了解决这个问题,MySQL中引入了changebuffer。changebuffer以前并不叫这个名字,以前叫insertbuffer,即只针对insert操作有效,现在改名叫changebuffer了,不仅仅针对insert有效,对delete和update操作也是有效的,changebuffer主要是对非唯一的索引有效,如果字段是唯一性索引,那么更新的时候要去检查唯一性,依然无法避免磁盘IO。
changebuffer就是说,当我们需要更改数据库中的数据的时候,我们把更改记录到内存中,等到将来数据被读取的时候,再将内存中的数据merge到bufferpool然后返回,此时bufferpool中的数据和磁盘中的数据就会有差异,有差异的数据我们称之为脏页,在满足条件的时候(redolog写满了、内存写满了、其他空闲时候),InnoDB会把脏页刷新回磁盘。这种方式可以有效降低写操作的磁盘IO,提升数据库的性能。
通过如下命令我们可以查看changebuffer的大小以及哪些操作会涉及到changebuffer:
innodb_change_buffer_max_size:这个配置表示changebuffer的大小占整个缓冲池的比例,默认值是25%,最大值是50%。innodb_change_buffering:这个操作表示哪些写操作会用到changebuffer,默认的all表示所有写操作,我们也可以自己设置为none/inserts/deletes/changes/purges等。不过changebuffer和bufferpool都涉及到内存操作,数据不能持久化,那么,当存在脏页的时候,MySQL如果突然挂了,就有可能造成数据丢失(因为内存中的数据还没写到磁盘上),但是我们在实际使用MySQL的时候,其实并不会有这个问题,那么问题是怎么解决的?那就得靠redolog了。
4.redolog的诞生在正式介绍redolog之前,还需要给大家普及一个概念:WAL。
WAL全称是Write-AheadLogging中文译作预写日志。啥意思呢?就是说MySQL的写操作并不是立刻更新到磁盘上,而是先记录在日志上,然后在合适的时间再更新到磁盘上,这样的好处是错开高峰期的磁盘IO,提高MySQL的性能。
配合上前面的bufferpool和changebuffer,WAL就是说在操作bufferpool和changebuffer之前,会先把记录写到redolog日志中,然后再去更新bufferpool或者changebuffer,这样,即使系统突然崩了,将来也可以通过redolog恢复数据。当然,redolog本身又分为:
日志缓冲(redologbuffer),该部分日志是易失性的。重做日志(redologfile),这是磁盘上的日志文件,该部分日志是持久的。那有人说,写redolog不就是磁盘IO吗?而写数据到磁盘也是磁盘IO,既然都是磁盘IO,那干嘛不把直接把数据写到磁盘呢?还费这事!
此言差矣。
写redolog跟写数据有一个很大的差异,那就是redolog是顺序IO,而写数据涉及到随机IO,写数据需要寻址,找到对应的位置,然后更新/添加/删除,而写redolog则是在一个固定的位置循环写入,是顺序IO,所以速度要高于写数据。
如前文所说,redolog涉及到两个东西:redologbuffer和redologfile,这两个东西我们分别来介绍。
4.1redologbuffer先来说redologbuffer。
我们说数据的变化先写入redolog中,并不是上来就写磁盘,也是先写到内存中,即redologbuffer,在时机成熟时,再写入磁盘,也就是redologfile。
我们先来看看redologbuffer有多大:
÷÷=16MB
可以看到,这个redologbuffer大小刚好是16MB,如果你觉得这个值有点小,也可以自行修改其大小。
数据的变更都会首先记录在这块内存中。小伙伴们知道,MySQL的增删改,如果我们没有显式的开启事务,MySQL内部也是有一个事务存在的,当内部这个事务