乐趣区

关于mysql:MySQL三大日志

前言

已知,在关系型数据库中的事务的 ACID 模型由 原子性 一致性 隔离性 持久性 组成,对于 MySQLInnoDB引擎,隔离性由基于乐观锁的 加锁机制 和基于无锁的 多版本并发管制 来反对,而原子性,则由在引擎层生成的 undo log 来保障,以及持久性,则是由在引擎层生成的 redo log 和在 Service 层生成的 binlog 来独特撑持,除此之外,在 Service 层生成的 binlog 还会用于 MySQL 的主从同步,所以 MySQL 中的 redo logbinlogundo log是非常重要的,本篇文章将对这三大日志进行学习。

MySQL版本:5.7

注释

一. MySQL 中的页

在学习三大日志之前,先理解一下 MySQL 中的页的概念。因为 InnoDB 引擎中将数据存储在磁盘上,所以为了防止读取数据时与磁盘频繁产生 IOInnoDB 引擎采纳页(Page)作为磁盘与内存交互的根本单位。每次会将一页数据加载到内存中,以晋升后续操作数据的效率。

InnoDB引擎 操作系统的文件管理系统 磁盘扇区 三者之间的关系能够用下图进行示意。

注:后续称 MySQL 中的页为 数据页

二. Buffer Pool

只管 InnoDB 每次读取数据都会将数据页加载到内存中,以缩小 IO 开销,然而如果每次都从磁盘读取数据页,效率也不会高,所以在 InnoDB 中退出了一个内存缓冲区,叫做Buffer Pool

读取数据时,先判断数据所在数据页是否存在于 Buffer Pool 中,如果存在于 Buffer Pool 中,则读取 Buffer Pool 中的数据,如果不存在于 Buffer Pool 中,则从磁盘上读取数据页,并将读取到的数据页写入Buffer Pool

批改数据时,也会先将批改写入到 Buffer Pool,而不会间接写入磁盘,此时就会呈现Buffer Pool 中的数据页内容和磁盘上的数据页的内容不统一的状况,此时称这样的数据页为 脏页 ,因而InnoDB 引擎提供了一个后盾线程每隔肯定工夫将 Buffer Pool 中的内容写入磁盘,这样的过程叫做 刷脏 ,通过Buffer Pool + 刷脏,能够实现一次性将多个批改同步到磁盘,从而缩小IO 次数,进步 InnoDB 引擎的读写效率。

批改数据时 InnoDB 引擎中基于 Buffer Pool 的交互流程图如下所示。

三. Redo Log

InnoDB存储引擎为了进步读写效率,引入了 Buffer Pool,当要操作的数据所在的数据页在Buffer Pool 中不存在时,会先将数据页从磁盘加载到 Buffer Pool 中,而后对 Buffer Pool 中的数据进行操作,此时会呈现脏页,所以 InnoDB 引擎提供了一个后盾线程以肯定的周期执行刷脏操作。然而刷脏并不是实时的,当 Buffer Pool 中存在脏页,此时 MySQL 服务端产生故障而宕机或重启,此时 Buffer Pool 中脏页所对应的那一部分数据批改就失落了。

为了解决数据失落的问题,InnoDB引入了 redo log(重做日志)来进行爱护。当对Buffer Pool 中的数据进行批改后,还会将对数据所做的批改写入 redo log 中,如果呈现了因为 MySQL 服务端宕机或者重启而导致数据失落的状况,此时能够在 MySQL 服务端启动的时候,从 redo log 进行数据的复原。实际上 redo log 也有一个缓冲区,叫做 redo log buffer,当要向redo log 记录信息时,会先记录到 redo log buffer 中,而后在适当的机会(可配)把 redo log buffer 的内容写入到磁盘上的 redo log 中。那么批改数据时 InnoDB 引擎中基于 Buffer Poolredo log buffer的交互流程图如下所示。

那么当初对于 redo log 有如下几点须要进行阐明。

1. 刷盘机会

注:上面提及的 page cache 能够了解为 OS 文件管理系统的缓冲区,在向磁盘写入数据时,会先写入到 page cache 中,而后再通过 fsync 函数将 page cache 中的内容刷到磁盘上。

InnoDB引擎中应用 innodb_flush_log_at_trx_commit 来设置 redo log 的刷盘机会策略,其能够设置反对三种策略。

  • innodb_flush_log_at_trx_commit为 0,示意每次提交事务时不会刷盘;
  • innodb_flush_log_at_trx_commit为 1,示意每次提交事务时会刷盘,即先将 redo log buffer 内容写入 page cache,而后调用fsync 函数将 page cache 中的内容刷到磁盘上;
  • innodb_flush_log_at_trx_commit为 2,示意每次提交事务时,仅将 redo log buffer 内容写入page cache

同时,InnoDB引擎有一个后盾线程,其 1 秒执行一次,会将 redo log buffer 的内容写入 page cache,而后再调用fsync 函数将 page cache 中的内容写到磁盘的 redo log 文件中,所以 innodb_flush_log_at_trx_commit 的值无论设置为 0,1 或者 2,最终都是能够将 redo log buffer 的内容写到磁盘的 redo log 文件中的。上面给出 innodb_flush_log_at_trx_commit 被设置为不同值时的刷盘示意图。

  • innodb_flush_log_at_trx_commit = 0
  • innodb_flush_log_at_trx_commit = 1
  • innodb_flush_log_at_trx_commit = 2

因而能够晓得,innodb_flush_log_at_trx_commit设置为 0 或者 2 时,在 MySQL 宕机时可能会造成 1 秒内的数据失落,而 innodb_flush_log_at_trx_commit 设置为 1 时,不会造成数据失落,innodb_flush_log_at_trx_commit=1也是 InnoDB 的默认设置。

最初,用一个图进行刷盘机会的总结。

2. redo log 文件模式

能够通过 SHOW VARIABLES LIKE 'innodb_log%' 语句查看 InnoDB 引擎中的 redo log 相干配置。下表是局部重要参数的阐明。

Variable_name 阐明 默认值
innodb_log_buffer_size redo log buffer的大小 16MB
innodb_log_file_size 每个 redo log 文件的大小 48MB
innodb_log_files_in_group redo log文件数量 2
innodb_log_group_home_dir redo log文件寄存门路 MySQL目录/data

所以 InnoDB 引擎中,默认状况下磁盘上的 redo log 文件个数为 2,每个 redo log 文件大小为 48MB,这两个 redo log 文件组成了一个 日志文件组,整体是一个环形构造,从头到尾进行循环写入,示意图如下。

在日志文件组中,有两个属性用于标识 以后写入地位 以后革除地位,阐明如下。

  • write pos。记录以后写入地位,写入后会向后推移;
  • checkpoint。记录以后革除地位,革除后会向后推移。

write poscheckpoint 之间的地位,示意 redo log 上能够写入的局部,如下所示。

如果 write pos 追上 checkpoint,此时须要革除redo log 内容以使得后续内容可能写入,具体做法是会先触发 Buffer Pool 的刷盘,而后就能够革除 checkpoint 之后的局部内容(这部分内容对应 Buffer Pool 刷到磁盘上的脏页),最初 checkpoint 向后推移,也就是说 checkpoint 之前的内容其实曾经被写入到了磁盘上,所以一旦 MySQL 宕机重启后须要依据 redo log 进行数据恢复时,只须要对 checkpoint 之后的内容进行复原。

3. 写 redo log 和写 dbfile 的区别

innodb_flush_log_at_trx_commit 参数设置为 1 时,每次提交事务后,会将 redo log buffer 中的内容写到 redo log 中,既然写到 redo log 也是向磁盘写数据,那么为什么不在提交事务后,间接将 Buffer Pool 中的内容写到 dbfile 呢。起因就是向 dbfile 写数据是随机 IO,向redo log 写数据是程序 IO,程序IO 的读写效率要高于随机IO

4. redo log 存储的数据组成

redo log中每条记录的组成为:表空间号 + 数据页号 + 偏移量 + 批改数据长度 + 批改的数据
redo log 属于 物理日志

四. Binlog

binlog是以事件的模式记录了所有的 DDLData Definition Language,数据定义语言)和DMLData Manipulation Language,数据操纵语言)语句,即binlog 记录的是操作而不是数据值,因而 binlog 属于逻辑日志。

不同于 redo log 的循环写入,binlog是追加写入,且没有固定大小限度。也不同于 redo log 属于 InnoDB 存储引擎,binlog是属于 MySQLService层,无论应用什么存储引擎,都会在 Service 层记录binlog

binlog能够用于 数据恢复 主从复制 ,次要就是通过读取binlog 并将 binlog 中记录的操作再执行一遍。

上面将从几个方面对 binlog 进行阐明。

1. 写入机会

当开启事务后,在事务执行过程中,会将 DDLDML的操作记录到 binlog cache 中,当提交事务时,就会将 binlog cache 中的内容先写到 page cache,而后通过fsync 函数将 page cache 的内容写到磁盘上的binlog

MySQL提供了 sync_binlog 参数来管制具体的写入策略,能够通过 SHOW VARIABLES LIKE 'sync_binlog%' 语句进行查看。sync_binlog参数的取值和阐明如下所示。

  • sync_binlog设置为 0,示意每次提交事务时,会将 binlog cache 的内容写入 page cache,而后由操作系统决定什么时候将page cache 的内容写到binlog
  • sync_binlog设置为 1,示意每次提交事务时,会将 binlog cache 的内容写入 page cache,而后调用fsync 函数将 page cache 的内容写到binlog
  • sync_binlog设置为 nn > 1),示意每次提交事务时,会将binlog cache 的内容写入 page cache,当向page cache 写入数据的事务达到 n 个,此时调用 fsync 函数将 page cache 的内容写到binlog

用下图进行概括示意。

2. 两阶段提交

当初已知,在开启事务后,因为后盾线程的存在,事务执行过程中是能够一直向 redo log 写入内容的,而 binlog 只能在事务提交时被写入,所以实际上 redo logbinlog的写入机会是不雷同的,这就导致当产生 MySQL 宕机时可能会呈现 redo logbinlog所蕴含的逻辑内容不统一的问题。

比方当初执行一条更新 SQL 语句 UPDATE student SET stu_age=22 WHERE id=1,如果这条语句的批改写到了redo log 中,然而在写到 binlogMySQL产生宕机,而后 MySQL 重启之后会依据 redo log 进行数据恢复,因为 redo log 中有更新 SQL 语句的批改数据,所以这条更新 SQL 语句的批改后果会写到磁盘中,然而 binlog 中是没有这条更新 SQL 语句的,就会导致后续基于 binlog 进行主从同步等操作时会呈现主和从数据不统一的问题。

为了解决上述的问题,在 InnoDB 引擎中,应用了两阶段提交来解决。具体的实现就是将 redo log 的写入分为两个阶段,示意图如下所示。

由上图可知,一条 redo log 记录能够由 事务 ID + redo log 记录数据 + 提交状态 组成,提交状态能够是 preparecommit,当第一次将一个数据批改写入 redo log 时,这条 redo log 记录的状态为 prepare,这是第一阶段提交,后续提交事务时,会在redo log 中将这个事务对应的记录的状态置为 commit,这是第二阶段提交。根据上述的两阶段提交的写入形式,再联合binlog,能够在产生MySQL 宕机导致 redo logbinlog逻辑内容不统一时判断事务是否须要进行回滚。具体的判断策略如下所示。

  • binlog无记录,redo log无记录。示意在第一阶段提交前产生宕机,此时须要回滚事务;
  • binlog无记录,redo log记录状态为 prepare。示意在binlog 写完之前产生宕机,此时须要回滚事务;
  • binlog有记录,redo log记录状态为 prepare。示意在binlog 写完之后,事务实现提交之前产生宕机,此时须要提交事务;
  • binlog有记录,redo log记录状态为commit。示意是失常实现的事务,此时无需进行操作。

五. Undo Log

undo log叫做 回滚日志 ,属于InnoDB 引擎。undo log记录了某条数据变更前的旧数据,当事务须要回滚时,能够通过 undo log 将数据恢复为事务批改前的数据,所以 InnoDB 引擎中应用 undo log 来保障了事务的原子性。

通常状况下,一条更新语句执行,写入三大日志的程序为 undo log 先于 redo logredo log 先于binlog

总结

本篇文章探讨的 MySQL 中的三大日志,指用于 数据恢复 redo log,用于 事务回滚 undo log,以及用于 数据恢复 主从同步 binlog

对于 redo log,其属于物理日志,由InnoDB 记录。在 InnoDB 引擎中向 redo log 写入数据时会先将数据写入 redo log buffer 内存中,并提供 innodb_flush_log_at_trx_commit 参数来设置刷盘机会,其能够设置反对三种策略,大节如下所示。

  • innodb_flush_log_at_trx_commit为 0,示意每次提交事务时不会刷盘;
  • innodb_flush_log_at_trx_commit为 1,示意每次提交事务时会刷盘,即先将 redo log buffer 内容写入 page cache,而后调用fsync 函数将 page cache 中的内容刷到磁盘上;
  • innodb_flush_log_at_trx_commit为 2,示意每次提交事务时,仅将 redo log buffer 内容写入page cache

对于 binlog,其属于逻辑日志,在MySQLService层记录。当向 binlog 写入数据时,会先将数据写入 binlog cache 内存中,并提供了 sync_binlog 参数来管制具体的写入策略,大节如下所示。

  • sync_binlog设置为 0,示意每次提交事务时,会将 binlog cache 的内容写入 page cache,而后由操作系统决定什么时候将page cache 的内容写到binlog
  • sync_binlog设置为 1,示意每次提交事务时,会将 binlog cache 的内容写入 page cache,而后调用fsync 函数将 page cache 的内容写到binlog
  • sync_binlog设置为 nn > 1),示意每次提交事务时,会将binlog cache 的内容写入 page cache,当向page cache 写入数据的事务达到 n 个,此时调用 fsync 函数将 page cache 的内容写到binlog

对于undo log,其用于事务回滚,能够参见 MySQL- 事务隔离级别与 MVCC 一文来理解其个性,本文不再赘述。

参考

MySQL 官网文档 -Redo Log
JavaGuide-MySQL 三大日志详解

退出移动版