MySQL日志——redo log和bin log的刷盘时机详解

我们先简单了解一下大致的刷盘时机,然后配合两阶段提交和组提交来看

redo log的刷盘时机

  1. MySQL 正常关闭时;
  2. 当 redo log buffer 中记录的写入量大于 redo log buffer内存空间的一半时,会触发落盘;
    PS:为什么这里要到一半就要刷了,因为redo log buffer是一个环状的内存结构,会被反复利用
  3. InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
  4. 由系统参数innodb_flush_log_at_trx_commit 参数控制。

其中,innodb_flush_log_at_trx_commit 参数控制,可取的值有:0、1、2,默认值为 1,这三个值分别代表的策略如下:
1、当设置该参数为 0 时,表示每次事务提交时将 redo log 留在 redo log buffer 中 ,该模式下在事务提交时不会主动触发写入磁盘的操作。
2、当设置该参数为 1 时,表示每次事务提交时,都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘,这样可以保证 MySQL 异常重启之后数据不会丢失。
3、当设置该参数为 2时,表示每次事务提交时,都只是缓存在 redo log buffer 里的 redo log 写到 redo log 文件,这并不意味着写入到了磁盘,而是写到了操作系统的Page Cache。

参数为1的时候会主动持久化到磁盘,但是0和2不会,那么这两个什么时候持久化到磁盘呢?

InnoDB 的后台线程每隔 1 秒:
(1)针对参数 0 :会把缓存在 redo log buffer 中的 redo log ,通过调用 write() 写到操作系统的 Page Cache,然后调用 fsync() 持久化到磁盘。所以参数为 0 的策略,MySQL 进程的崩溃会导致上一秒钟所有事务数据的丢失;
(2)针对参数 2 :调用 fsync,将缓存在操作系统中 Page Cache 里的 redo log 持久化到磁盘。所以参数为 2 的策略,较取值为 0 情况下更安全,因为 MySQL 进程的崩溃并不会丢失数据,只有在操作系统崩溃或者系统断电的情况下,上一秒钟所有事务数据才可能丢失。

我们可以通过系统变量来查看这个参数

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.00 sec)

好了,redo log介绍完了,接着我们来介绍bin log的刷盘时机。

bin log的刷盘时机

每个线程有自己 binlog cache,最终会都写到同一个 binlog 文件。

binlog的刷盘过程:
(1) write,指的就是指把日志写入到 binlog 文件,但是并没有把数据持久化到磁盘,因为数据还缓存在文件系统的 page cache 里,write 的写入速度还是比较快的,因为不涉及磁盘 I/O。
(2)fsync,才是将数据持久化到磁盘的操作,这里就会涉及磁盘 I/O,所以频繁的 fsync 会导致磁盘的 I/O 升高。

那么什么时候刷盘呢?
通过sync_binlog 参数来控制数据库的 binlog 刷到磁盘上的频率:

1、sync_binlog = 0 的时候,表示每次提交事务都只 write,不 fsync,后续交由操作系统决定何时将数据持久化到磁盘;
2、sync_binlog = 1 的时候,表示每次提交事务都会 write,然后马上执行 fsync;
3、sync_binlog= N (N>1) 的时候,表示每次提交事务都 write,但累积 N 个事务后才 fsync。

我们通过命令行来查看参数:

mysql> show variables like '%sync_binlog%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog   | 1     |
+---------------+-------+
1 row in set (0.00 sec)

两次提交、组提交、双参数配合实现了两个日志的同步

有了前面两个刷盘时机,为什么还要有两次提交,因为我们需要保证redo log和bin log的一致性
两阶段提交的过程是如何的?
具体的取决于我们的参数,参数一共有四个分别如下所示:

mysql> show variables like '%sync_binlog%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog   | 1     |
+---------------+-------+
1 row in set (0.00 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.00 sec)

mysql> show variables like '%binlog_group%';
+-----------------------------------------+---------+
| Variable_name                           | Value   |
+-----------------------------------------+---------+
| binlog_group_commit_sync_delay          | 1000000 |
| binlog_group_commit_sync_no_delay_count | 10      |
+-----------------------------------------+---------+
2 rows in set (0.00 sec)

其中,我们看到了两个新参数,他们是组提交参数:

1、 binlog_group_commit_sync_delay= N,表示在等待 N 微妙后,直接调用 fsync,将处于文件系统中 page cache 中的 binlog 刷盘,也就是将binlog 文件持久化到磁盘。表中值为1000000 (即1e6),就是1s。
2、 binlog_group_commit_sync_no_delay_count = N,表示如果队列中的事务数达到 N个,就忽视binlog_group_commit_sync_delay 的设置,直接调用 fsync,将处于文件系统中 page cache中的 binlog 刷盘。

不同的参数效果都是不一样的。

1、我们先来看最经典的双1配置
此刻事务提交时需要花费1.00 sec,因为binlog_group_commit_sync_delay设置的是1s,binlog_group_commit_sync_no_delay_count和binlog_group_commit_sync_delay满足其中一条即可

2、在双1的基础上,如果我们把innodb_flush_log_at_trx_commit改了呢?
每次redo log都没有刷盘,我们默认就成功了。

3、在双1的基础上,如果我们把sync_binlog改了呢?
此时事务提交只需要0.00sec,可以判定提交的瞬间未刷盘,但是提交成功了。因为sync_binlog=N,在后续的1~N-1的事务,commit都是很快,第N个事务commit所消耗的时间是1s左右。也就是在第N次时候,进行了刷盘。
这时候有人疑惑了,那么我的组提交参数有啥用?
我们来看结论:
开启两个并行的窗口,这两个窗口同时commit提交,并设置binlog_group_commit_sync_no_delay_count =2,我们发现刷盘了。 也就是说组提交在事务并行的时候才有效果。为什么要在并行事务的时候才有效果?

原来,早期的 MySQL 版本中,通过使用 prepare_commit_mutex 锁来保证事务提交的顺序,在一个事务获取到锁时才能进入
prepare 阶段,一直到 commit 阶段结束才能释放锁,下个事务才可以继续进行 prepare 操作。
通过加锁虽然完美地解决了顺序一致性的问题,但在并发量较大的时候,就会导致对锁的争用,性能不佳。

所以sync_binlog和组提交之间是相互配合而不是冲突矛盾的关系,在事务并发时组提交生效,而在没有并发时候,syc_binlog就发挥了巨大作用。

好了,关于日志刷盘的内容就到这了。

相关推荐

  1. redolog、undologbinlog日志文件详解

    2024-03-30 21:36:03       13 阅读
  2. Mysql日志binlogredolog、undolog

    2024-03-30 21:36:03       32 阅读
  3. MySQL日志——redo logbin log时机详解

    2024-03-30 21:36:03       19 阅读
  4. MySQLbinlogredolog有什么区别?

    2024-03-30 21:36:03       15 阅读
  5. mysql-binlogredolog undolog区别

    2024-03-30 21:36:03       40 阅读
  6. 如何解析Mysqlbinlog日志

    2024-03-30 21:36:03       19 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-30 21:36:03       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-30 21:36:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-30 21:36:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-30 21:36:03       20 阅读

热门阅读

  1. 乐观锁的简单感悟

    2024-03-30 21:36:03       20 阅读
  2. 【python】一些常用的小脚本

    2024-03-30 21:36:03       20 阅读
  3. 大三实习小菜蛋之document元素节点

    2024-03-30 21:36:03       17 阅读
  4. Express

    Express

    2024-03-30 21:36:03      18 阅读
  5. C++知识点总结(27):链表

    2024-03-30 21:36:03       16 阅读
  6. math模块篇(八)

    2024-03-30 21:36:03       16 阅读
  7. vue 通过插槽来分配内容

    2024-03-30 21:36:03       15 阅读
  8. SQL中添加数据的方式

    2024-03-30 21:36:03       14 阅读
  9. 基于IvorySQL+Patroni+vip-manager构建高可用集群

    2024-03-30 21:36:03       15 阅读
  10. Flutter页面生命周期

    2024-03-30 21:36:03       16 阅读