redo日志(有问题,待修改)
redo日志(物理日志)
InnoDB存储引擎是以页为单位来管理存储空间的,我们进行的增删改查操作都是将页的数据加载到内存中,然后进行操作,再将数据刷回到硬盘上。
那么问题就来了,如果我要给张三转账100块钱,事务已经提交了,这个时候InnoDB把数据加载到内存中,这个时候还没来得及刷入硬盘,突然停电了,数据库崩了。重启之后,发现我的钱没有转成功,这不是尴尬了吗?
解决方法很明显,我们在硬盘加载到内存之后,进行一系列操作,一顿操作猛如虎,还未刷新到硬盘之前,先记录下,在XXX位置我的记录中金额减100,在XXX位置张三的记录中金额加100,然后再进行增删改查操作,最后刷入硬盘。如果未刷入硬盘,在重启之后,先加载之前的记录,那么数据就回来了。
这个记录就叫做重做日志,即redo日志。他的目的是想让已经提交的事务对数据的修改是永久的,就算他重启,数据也能恢复出来。
log buffer(日志缓冲区)
为了解决磁盘速度过慢的问题,redo日志不能直接写入磁盘,咱先整一大片连续的内存空间给他放数据。这一大片内存就叫做日志缓冲区,即log buffer。到了合适的时候,再刷入硬盘。至于什么时候是合适的,这个下一章节说。
我们可以通过show VARIABLES like 'innodb_log_buffer_size'
命令来查看当前的日志缓存大小,下图为线上的大小。
redo日志刷盘时机
由于redo日志一直都是增长的,且内存空间有限,数据也不能一直待在缓存中, 我们需要将其刷新至硬盘上。
那什么时候刷新到硬盘呢?
- log buffer空间不足。上面有指定缓冲区的内存大小,MySQL认为日志量已经占了 总容量的一半左右,就需要将这些日志刷新到磁盘上。
- 事务提交时。我们使用redo日志的目的就是将他未刷新到磁盘的记录保存起来,防止 丢失,如果数据提交了,我们是可以不把数据提交到磁盘的,但为了保证持久性,必须 把修改这些页面的redo日志刷新到磁盘。
- 后台线程不同的刷新 后台有一个线程,大概每秒都会将log buffer里面的redo日志刷新到硬盘上。
- checkpoint 下下小节讲
redo日志文件组
我们可以通过show variables like 'datadir'
命令找到相关目录,底下有两个文件, 分别是ib_logfile0和ib_logfile1,如下图所示。
我们将缓冲区log buffer里面的redo日志刷新到这个两个文件里面,他们写入的方式 是循环写入的,先写ib_logfile0,再写ib_logfile1,等ib_logfile1写满了,再写ib_logfile0。 那这样就会存在一个问题,如果ib_logfile1写满了,再写ib_logfile0,之前ib_logfile0的内容 不就被覆盖而丢失了吗? 这就是checkpoint的工作啦。
checkpoint
redo日志是为了系统崩溃后恢复脏页用的,如果这个脏页可以被刷新到磁盘上,那么 他就可以功成身退,被覆盖也就没事啦。
冲突补习
从系统运行开始,就不断的修改页面,会不断的生成redo日志。redo日志是不断 递增的,MySQL为其取了一个名字日志序列号Log Sequence Number,简称lsn。 他的初始化的值为8704,用来记录当前一共生成了多少redo日志。
redo日志是先写入log buffer,之后才会被刷新到磁盘的redo日志文件。MySQL为其 取了一个名字flush_to_disk_lsn。用来说明缓存区中有多少的脏页数据被刷新到磁盘上啦。 他的初始值和lsn一样,后面的差距就有了。
做一次checkpoint分为两步
- 计算当前系统可以被覆盖的redo日志对应的lsn最大值是多少。redo日志可以被覆盖, 意味着他对应的脏页被刷新到磁盘上,只要我们计算出当前系统中最早被修改的oldest_modification, 只要系统中lsn小于该节点的oldest_modification值磁盘的redo日志都是可以被覆盖的。
- 将lsn过程中的一些数据统计。
作者:学习Java的小姐姐
链接:https://juejin.im/post/5dfc846051882512327a63b6
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。