全流程
我们执行增删改操作的时候,首先会在Buffer Pool中加独占锁更新缓存页,那么缓存页和底层的物理磁盘上的数据页的原理,在更新完Buffer Pool中的缓存页之后,必须要写一条redo log,这样才能记录下来我们对数据库做的修改。redo log可以保证我们事务提交之后,如果事务中的增删改SQL语句更新的缓存页还没刷到磁盘上去,此时MySQL宕机了,那么MySQL重启过后,就可以把redo log重做一遍,恢复出来事务当时更新的缓存页,然后再把缓存页刷到磁盘就可以了redo log本质是保证事务提交之后,修改的数据绝对不会丢失的。
redo log作用
一个事务里有增删改SQL更新了缓存页,然后事务提交了,结果万一你还没来得及让IO线程把缓存页刷新到磁盘文件里,此时MySQL宕机了,然后内存数据丢失,事务提交的时候把修改过的缓存页未刷入磁盘,你事务更新的数据就丢失了,所以此时才会引入一个redo log机制,这个机制就是说,你提交事务的时候,绝对是保证把你对缓存页做的修改以日志的形式,写入到redo log日志文件里去的;另一方面,redo log写日志,是顺序写入磁盘文件,每次都是追加到磁盘文件末尾去,速度很快,提交事务的时候,用redo log的形式记录下来你做的修改,性能会远远超过刷缓存页的方式,这也可以让数据库的并发能力更强;
redo log里本质上记录的就是在对某个表空间的某个数据页的某个偏移量的地方修改了几个字节的值,具体修改的值是什么,他里面需要记录的就是表空间号 数据页号 偏移量 修改几个字节的值 具体的值;
redo log block
平时数据不是存放在数据页的,用一页一页的数据页来存放数据。那么对于redo log也不是单行单行的写入日志文件的,他是用一个redo log block来存放多个单行日志的。
一个redo log block是512字节,这个redo log block的512字节分为3个部分,一个是12字节的header块头,一个是496字节的body块体,一个是4字节的trailer块尾,header头又分为了4个部分:
- 包括4个字节的block no,就是块唯一编号;
- 2个字节的data length,就是block里写入了多少字节数据;
- 2个字节的first record group。这个是说每个事务都会有多个redo log,是一个redo log group,即一组redo log。那么在这个block里的第一组redo log的偏移量,就是这2个字节存储的;
- 4个字节的checkpoint on
一个block最多放496自己的redo log日志
redo log数据 ==== > redo log block ==== > redo log文件,redo log数据先写入redo log block数据结构里去,然后等内存里的一个redo log block的512字节都满了,再一次性把这个redo log block写入磁盘文件;
redo log buffer
redo log buffer其实就是MySQL在启动的时候,就跟操作系统申请的一块连续内存空间,里面划分出了N多个空的redo log block,大概可以认为相当于是bufferpool。那个buffer pool是申请之后划分了N多个空的缓存页和一些链表结构,把磁盘上的数据页加载到内存里来,通过设置mysql的innodb_log_buffer_size可以指定这个redo log buffer的大小,默认的值就是16MB。
redo log buffer中所有的redo log block都写满,会强制把redo log block刷入到磁盘中去;平时执行一个事务的过程中,每个事务会有多个增删改操作,那么就会有多个redo log,这多个redo log就是一组redo log,其实每次一组redo log都是先在别的地方暂存,然后都执行完了,再把一组redolog给写入到redo log buffer的block里去。
redo log buffer缓冲刷盘时机
(1)如果写入redo log buffer的日志已经占据了redo log buffer总容量的一半了,也就是超过了8MB的redo log在缓冲里了,此时就会把他们刷入到磁盘文件里去;
(2)一个事务提交的时候,必须把他的那些redo log所在的redo log block都刷入到磁盘文件里去,只有这样,当事务提交之后,他修改的数据绝对不会丢失,因为redo log里有重做日志,随时可以恢复事务做的修改(PS:当然,之前最早最早的时候,这个redo log哪怕事务提交的时候写入磁盘文件,也是先进入os cache的,进入os的文件缓冲区里,所以是否提交事务就强行把redo log刷入物理磁盘文件中,这个需要设置对应的参数);
(3)后台线程定时刷新,有一个后台线程每隔1秒就会把redo log buffer里的redo log block刷到磁盘文件里去;
(4)MySQL关闭的时候,redo log block都会刷入到磁盘里去;
绝对保证数据不丢,还得配置一个参数,提交事务把redo log刷入磁盘文件的os cache之后,还得强行从os cache刷入物理磁盘。
redo log写入日志文件,那对磁盘占用空间越来越大,可以通过innodb_log_group_home_dir参数来设置这个目录的。然后redo log是有多个的,写满了一个就会写下一个redo log,而且可以限制redo log文件的数量,通过innodb_log_file_size可以指定每个redo log文件的大小,默认是48MB,通过innodb_log_files_in_group可以指定日志文件的数量,默认就2个;