redolog的写入机制

10 分钟阅读 727 字 + 744 词
redo log有三种状态
img
这三种状态分别是:
存在 redo log buffer 中,物理上是在 MySQL 进程内存 中,就是图中的红色部分;
写到磁盘 (write) ,但是没有 持久化(fsync) ,物理上是在 文件系统的 page cache 里面,也就是图中的黄色部分;
持久化到磁盘 ,对应的是 hard disk,也就是图中的绿色部分。
日志写到 redo log buffer 是很快的,wirte 到 page cache 也差不多,但是持久化到磁盘的速度就慢多了。
为了控制 redo log 的写入策略,InnoDB 提供了 innodb_flush_log_at_trx_commit 参数,它有三种可能取值:
  • 设置为 0 的时候,表示 每次事务提交时都只是把 redo log 留在 redo log buffer 中 ;
  • 设置为 1 的时候,表示 每次事务提交时都将 redo log 直接持久化到磁盘
  • 设置为 2 的时候,表示 每次事务提交时都只是把 redo log 写到 page cache
InnoDB 有一个后台线程, 每隔 1 秒 就会把 redo log buffer 中的日志 调用 write 写到文件系统的 page cache,然后调用 fsync 持久化到磁盘。
注意, 事务执行中间过程的 redo log 也是直接写在 redo log buffer 中的,这些 redo log 也会被后台线程一起持久化到磁盘 。也就是说,一个没有提交的事务的 redo log,也是可能已经持久化到磁盘的。
实际上,除了后台线程每秒一次的轮询操作外,还有两种场景会让一个没有提交的事务的 redo log 写入到磁盘中。
一种是, redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动写盘 。注意,由于这个事务并没有提交,所以这个写盘动作只是 write,而没有调用 fsync,也就是只留在了文件系统的 page cache。
另一种是, 并行的事务提交的时候,顺带将这个事务的 redo log buffer 持久化到磁盘 。假设一个事务 A 执行到一半,已经写了一些 redo log 到 buffer 中,这时候有另外一个线程的事务 B 提交,如果 innodb_flush_log_at_trx_commit 设置的是 1,那么按照这个参数的逻辑,事务 B 要把 redo log buffer 里的日志全部持久化到磁盘。这时候,就会带上事务 A 在 redo log buffer 里的日志一起持久化到磁盘。
img
我们介绍两阶段提交的时候说过, 时序上 redo log 先 prepare, 再写 binlog,最后再把 redo log commit。
如果把 innodb_flush_log_at_trx_commit 设置成 1 ,那么 redo log 在 prepare 阶段就要持久化一次 ,因为有一个崩溃恢复逻辑是要依赖于 prepare 的 redo log,再加上 binlog 来恢复的。
每秒一次后台轮询刷盘,再加上崩溃恢复这个逻辑,InnoDB 就认为 redo log 在 commit 的时候就 不需要 fsync 了,只会 write 到文件系统的 page cache 中就够了。
现在你就能理解了,WAL 机制主要得益于两个方面:
redo log 和 binlog 都是顺序写,磁盘的顺序写比随机写速度要快
组提交机制 ,可以大幅度降低磁盘的 IOPS 消耗。

目录