redo log是什么
redo log也叫重做日志,是Innodb存储引擎MySQL提供了崩溃恢复的能力,实现了事务的持久性。
InnoDB的事务采用了WAL技术(Write-Ahead Logging)既先写日志,再写磁盘。MySQL每执行一条DML语句,先将记录写入内存分配redo log buffer中,后续再一次性将redo log buffer中的内容写到redo log文件中,而被修改的数据页由checkpoint机制保证最终落盘。
为什么引入redo log?
存在的问题
首先Innodb是以页为单位来进行磁盘IO,页的大小默认为16KB。在需要访问页时,要先将页从磁盘上缓存到内存中的Buffer Pool这个缓冲池
变更之后的页就形成了脏页,缓冲池会以一定的频率(checkPoint机制)将脏页刷新到磁盘。缓冲池的目的是有效减轻CPU和磁盘之间的速度差带来的性能影响。
但是由于脏页刷入磁盘不是每次变更后立即触发的,而是由master线程间隔一段时间去处理的,这就可能在事务提交之后刚写完缓冲区,此时MySQL宕机了,就会丢失这部分数据,这不符合事务的持久性要求。
如果在页变更后立即刷入磁盘又会影响性能,因为修改一个字节都会刷新16KB的数据到磁盘上,而且有些事务会涉及到多个页的数据,将这些页刷入磁盘需要进行多次随机IO操作是十分耗时的。
此时的解决方案就是先将变更的内容记录下来,例如:将第2页面中偏移量为50处的字节值由0变为1,此时可以记录为:将0号表空间

redo log的好处
- 降低刷盘频率:变更日志先行存入
redo log buffer,脏页刷盘和redo log buffer刷盘时机可控; - 日志占用空间小:存储表空间
ID、页号、偏移量和需要更新的值。

刷盘策略
redo log的写入为了减少刷盘频率需要先写入内存的redo log buffer中,之后以一定的频率将buffer刷入到磁盘的redo log文件中去。
InnoDB 存储引擎为 redo log 的刷盘策略提供了三种策略,使用innodb_flush_log_at_trx_commit 参数配置,有以下三种取值:
| 取值 | 含义 | 优点 | 缺点 |
|---|---|---|---|
| 0 | 表示每次事务提交时不进行刷盘操作,由master线程每隔1s进行一次刷盘。 | IO效率高于1,低于2(注:0的IO频率是1s一次,2的IO频率由OS决定) | 数据库 |
| 1 | 表示每次事务提交时都将进行刷盘操作(默认值)。 | 宕机不会丢失数据,保障了持久性 | 效率最差 |
| 2 | 表示每次事务提交时都只把redo log buffer内容写入操作系统的page cache,由OS决定什么时候同步到磁盘文件 | IO效率最高,仅数据库宕机不会丢失数据 | 操作系统宕机会丢失1s数据,无法保证持久性 |
innodb_flush_log_at_trx_commit=0
事务过程中,redo log写入redo log buffer中,由master线程每隔1s调用fsync操作将buffer中的内容写到操作系统的page cache中。MySQL宕机会造成1s的事务丢失。

innodb_flush_log_at_trx_commit=1
事务提交时,主动刷盘redo log buffer的内容立刻同步到磁盘文件中,操作系统宕机不会丢失数据;
事务未提交时,操作系统宕机redo log buffer丢失也不会有损失,因为事务未提交不会持久化。

innodb_flush_log_at_trx_commit=2
事务提交就将redo log buffer中的内容写入page cache缓存,由操作系统决定什么时候将page cache的内容写入磁盘。此时MySQL宕机并不会丢失数据,但是操作系统宕机会丢失这1s的数据。

日志文件 组
redo log文件不止一个,而是以文件组的形式出现,文件大小redo log文件大小之和。它们采用循环链表redo log日志文件组写入数据。

在整个日志文件组中还有两个重要的属性:
write pos是当前记录的位置,一边写一边后移;checkpoint是当前要擦除的位置,也是往后推移。
每次刷盘redo log记录到日志文件组中,write pos位置就会后移更新。
每次MySQL通过日志文件组恢复数据之后,这部分日志不再需要,会清空加载过的redo log记录,并把checkpoint后移更新。
write pos和checkpoint之间为空闲部分可以用来写入新的redo log记录。

当redo log组被写满时,既write pos追上了checkpoint,此时不能再写入新的redo log,需要MySQL清空一些记录,留出新的空间。

redo log相关配置
日志缓存区大小
默认16M,最大4096M,最小值为1M。
mysql> show variables like'%innodb_log_buffer_size%';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| innodb_log_buffer_size | 1048576 |
+------------------------+---------+
1 row in set (0.02 sec)文件位置
默认值为.\,表示在数据库的数据目录(见配置datadir = C:\DevTools\mysql-5.7\data)下。mysql> show variables like'%innodb_log_group_home_dir%';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| innodb_log_group_home_dir | .\ |
+---------------------------+-------+
1 row in set (0.02 sec)文件数量
默认数量为2,命名方式如下:ib_logfile0,ib_logfile1...
mysql> show variables like'innodb_log_files_in_group';
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| innodb_log_files_in_group | 2 |
+---------------------------+-------+
1 row in set (0.02 sec)日志文件大小
单个redo log文件设置大小,默认值为48M,最大值为512G既(innodb_log_files_in_group*innodb_log_file_size)不能大于512G。
mysql> show variables like 'innodb_log_file_size';
+----------------------+----------+
| Variable_name | Value |
+----------------------+----------+
| innodb_log_file_size | 50331648 |
+----------------------+----------+
1 row in set (0.03 sec)刷盘策略
mysql> show variables like 'innodb_flush_log_at_trx_commit';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1 |
+--------------------------------+-------+
1 row in set (0.03 sec)



