redo log 是什么?
为了确保数据不丢失,MySQL引入了 redo log 机制。在事务提交之前,必须写一条 redo log,redo log 写入成功才表明事务提交成功。redo log 会用磁盘顺序读写的形式往磁盘写数据,所以速度也是非常快的。
redo log 写入成功后,但是 buffer pool 里面的内存页还没有刷回磁盘的时候,服务器宕机了,重启后,也会根据 redo log 进行内存页中的数据恢复。所以保证了数据不会丢失。
redo log 本质上记录了某个表空间的某个数据页的某个偏移量的地方,改了几个字节的值,具体的值是什么。格式大致为 “表空间号 + 数据页号 + 偏移量 + 修改几个字节的值 + 具体的值“。
更具体一些,redo log 根据修改字节的个数来区分类型,MLOG_1BYTE 类型就是修改了1个字节的值,MLOG_2BYTE 类型的日志指的就是修改了 2 个字节的值。还有4个字节,8个字节等。如果是大量字符对应的是 MLOG_WRITE_STRING 类型。所以,redo log 日志更规范一些的格式大概是这样:日志类型,表空间ID,数据页号,数据页中的偏移量,具体修改的数据。如果是 MLOG_WRITE_STRING 类型,还会多一个修改数据长度。
redo log 是如何写入磁盘的?
redo log 写入磁盘的时候,并不是逐条写入磁盘文件的,而是先写入一个 redo log block 数据结构中,然后再将 redo log block 写入磁盘文件中。先来分析一下 redo log block 。redo log block 由3个部分组成,分别是 header , body , trailer 。一共512个字节,结构大概如下:
| header 12字节 |
块编号 4字节 |
已经写入数据长度 2字节 |
第一个日志分组偏移量 2字节 |
check point no 4字节 |
|---|---|---|---|---|
| body | 496字节 | |||
| trailer | 4字节 |
- block no :块的唯一编号
- data length :记录 block 写入了多少字节的数据
- first record group :???
- checkpoint no :???
redo log block 也有类似 buffer pool 这样的内存缓冲池的概念。MySQL 启动的时候,也会在内存中申请一片空间,这些空间叫做 redo log buffer ,包含着多个 redo log block 。redo log buffer 默认的大小为16M,可以通过参数 innodb_log_buffer_size 来调整大小。
redo log 会写入在 block 的 body 中。执行事务的时候,会产生多个 redo log ,这些 redo log 就会组成一组,这一组 redo log 会在别的地方暂存,然后执行完毕后,再把一组的 redo log 写入到 block 中。如果一组 redo log 太大,会存放在2个 block 中,如果比较小的话,1个 block 也会存在多个 redo log 组。
写 redo log 日志的时候,先往内存中的 redo log buffer 中的 block 写数据,达到某些条件后,就会将redo log buffer 中的 block 刷回磁盘。以下几种情况的时候,会将内存中的 block 刷回磁盘:
- 后台有一个线程,每秒将内存的 block 写入到磁盘文件中对应的 block。
- 写入的 redo log 的大小,超过 redo log buffer 容量的一半(默认8M),就会强制刷回磁盘。
- 一个事务提交的时候,必须将这个事务的 redo log 所在的 block 刷回磁盘文件。这样才可以保证数据不丢失。
- MySQL 关闭的时候,也会将 block 刷回磁盘。
值得注意的一点是,写入磁盘的时候,会先写入操作系统的缓存,即OS Cache ,然后再刷入磁盘。
什么时候将 OS Cache 刷入磁盘,MySQL 提供了参数 innodb_flush_log_at_trx_commit 让用户决定。
- 0:表示事务提交后,不进行 fsync,而是由 master 每隔 1s 进行一次重 redo log 的 fysnc
- 1:默认值,每次事务提交的时候同步进行 fsync
- 2:写入 os cache 后,交给操作系统自己决定什么时候 fsync
redo log 磁盘文件的处理
redo log 不停的写入磁盘文件后,磁盘文件当然也不会是无限增加的。默认情况下,redo log 会写入一个目录中的文件里,这个目录可以通过 “show variables like ‘datadir’” 来查看,也可以通过 innodb_log_group_home_dir 这个参数来设置目录。
redo log 的磁盘文件默认是有2个,每个48M。可以通错参数 innodb_log_file_size 指定每个文件的大小,通过参数 innodb_log_files_in_group 指定日志文件的数量。默认的这两个文件分别为:ib_logfile0 和 ib_logfile1 。内存中的 bolck 往磁盘中写入的时候先写第1个,然后写满了以后再写第2个,如果第2个也写满了,就会继续写入第1个,覆盖第1个文件的原先的内容。按照这样的机制循环写入。
