MySQL redo log与binlog

724 阅读7分钟

这篇依旧算是学习心得分享

1. 前言

刘能是家中的长子,由于父亲年纪越来越大,家里唯一的小酒馆也需要他来接手了,随着刘能自己努力的经营,酒馆的生意蒸蒸日上,但是问题也随之而来,因为可以赊账,每次有客人点完菜后赊账时,都需要去厚厚的账本中去记录,刘能发现自己根本忙不过来了。
某天刘能灵光一现,去村头买了一块小黑板,白天营业的时候一旦有客人赊账,刘能准备了两种方案:

  1. 所有赊账记录都直接写道小黑板上晚上打样后把小黑板上的记录再写道账本上去
  2. 白天生意要是过于火爆, 小黑板上写满时,擦去一部分赊账记录并同步到账本上后再继续用小黑板记录

2. 什么是redo log?

MySQL 5.7 Reference Manual :: 14.6.6 Redo Log - MySQL
A disk-based data structure used during crash recovery, to correct data written by incomplete transactions. During normal operation, it encodes requests to change InnoDB table data, which result from SQL statements or low-level API calls through NoSQL interfaces. Modifications that did not finish updating the data files before an unexpected shutdown are replayed automatically.
描述的比较清楚,就是说redo log也就是重做日志是一种基于磁盘的数据结构,用于故障修复。
注意:redo log是由Innodb引擎独有的数据结构

2.1 redo log 相关参数

在Innodb中可是使用
innodb_log_files_in_group 配置redo log文件个数
innodb_log_file_size 配置每一个文件的大小

2.2 redo log 写入磁盘规则

为了确保每次日志都能写入到事务日志文件中,在每次将log buffer中的日志写入日志文件中的过程中,都会调用一次操作系统的fsync操作。Mysql是工作在用户空间的,所以log buffer处于用户空间的内存中。要写入磁盘中的log file中,中间需要经过操作系统的内核空间os buffer,调用fsync将OS buffer中的日志刷到磁盘中的log file中。

通过参数innodb_flush_log_at_trx_commit设置在commit时如何将log buffer的日志刷入log file中

  • 当设置为0的时候,事务提交时不会将log buffer中的日志写入到OS buffer,而是每秒写入OS buffer,并调用fsync()写入到log file中。也就是说设置为0时,系统崩溃,会丢失1秒的数据。
  • 当设置为1的时候,事务每次提交都会将log buffer中的日志写入OS buffer并调用fsync()刷到log file中。这种方式即使系统崩溃都不会丢失数据,但是每次提交都写入磁盘,IO的性能较差。
  • 当设置为2的时候,每次提交都仅写入到OS buffer,然后每秒调用fsync()将OS buffer中的日志写入log file on disk。

按照2.1参数配置中设置innodb_log_files_in_group 为4,innodb_log_file_size为1G,那么此时redo log总大小为4个G,下图为数据写入磁盘时的示意图:

write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。
checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
这里redo log就好比我们在前言中提到的小黑板,在不断的往小黑板记录时,write pos和check point之间的内容(图中的标黄区域)代表着小黑板空着部分可以写赊账记录,如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

3. 什么是binlog?

MySQL 5.7 Reference Manual :: 5.4.4 The Binary Log - MySQL

The binary log contains “events” that describe database changes such as table creation operations or changes to table data.It also contains events for statements that potentially could have made changes........

  • For replication, the binary log on a master replication server provides a record of the data changes to be sent to slave servers. The master server sends the events contained in its binary log to its slaves, which execute those events to make the same data changes that were made on the master. See Section 16.2, “Replication Implementation”.
  • Certain data recovery operations require use of the binary log. After a backup has been restored, the events in the binary log that were recorded after the backup was made are re-executed. These events bring databases up to date from the point of the backup. See Section 7.5, “Point-in-Time (Incremental) Recovery Using the Binary Log”.

描述如下,binlog也称为归档日志包含了描述如表创建或表格数据变更的数据库变更事件,它还包含针对可能进行了更改的语句的事件。binlog是逻辑日志,而上面对照的redo log对应的物理日志,记录的类似是“在某个数据页进行了什么修改”
下面还有两个重点提到的binlog存在的目的:

  • 用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
  • 用于数据库的基于时间点的还原。

注意:binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。

3.1 binlog 相关参数

max_binlog_size binlog 采用的是追加方式进行写入,这个参数可以设置每个binlog文件大小,当文件大小超过该值时,会创建新的文件进行追加写入
sync_binlog 这个参数设置成 1 的时候,表示每次事务的 binlog 都持久化到磁盘

4. 正文

上面已经大致对介绍了redo log与binlog,其中redo log对应了前言中提到的小黑板,那么对应的磁盘中的数据就是我们掌柜刘能的账本了,小黑板和账本配合的整个过程,其实就是 MySQL 里说到的 WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写粉板,等不忙的时候再写账本。在MySQL Innodb引擎中这个数据是如何记录到小黑板上呢?binlog又在里面起到了什么作用呢?

我们先来看一张流程图

粗略的列出10个步骤其中第六步 写入redo log设置状态为prepare和第10步将记录变更为commit我们称之为redo log的两阶段提交,那么为什么要这样设计呢?我们进行几个场景进行模拟

  • 场景1. 在上述流程图中第6步之前,发生了断电导致数据库异常关闭,那么此时在重启后使用binlog恢复数据时发现binlog中并没有这条记录,那么代表着更新操作确实没有执行完毕,数据库中的数据也就没有发生变动
  • 场景2. 在上述流程图中第7步时,数据库发生异常关闭,重启后发现binlog中没有信息,但redo log存在着一条prepare状态的记录,此时直接回滚信息清除该条记录
  • 场景3. 在上述流程图中第9步时,数据库异常关闭,重启后发现binlog存在信息,且redo log存在对应的状态为prepare状态的记录,恢复数据自动将prepare记录变更为commit,数据一致

因为两阶段提交的技术,从而完美的避免了在数据库发生异常时,redo log与binlog信息不一致的问题。
或许有人问了redo log已经存了物理逻辑,那么我为啥还要用binlog?

    1. redo log的大小是固定的,采用的是循环写入,日志会被覆盖掉,无法用于数据回滚/数据恢复等操作。
    1. redo log是Innodb引擎层实现的,并不是所有引擎都有。

binlog是我们在进行数据恢复或主从同步时核心依据日志,是由MySQL Server层实现所有引擎通用,且是一种逻辑日志,使用了追加写
redo log是Innodb引擎中用于故障修复时的日志,同时基于WAL技术也大大提升了数据库的执行效率,它只存在与Innodb引擎中,是一种物理日志,采用的是循环写

5. 写在最后

大家注意到了,前面描述的将小黑板数据同步到账本这一动作并没有说明,这个就是对应事务脏页写入磁盘后,redo log日志空间将被释放,这一个过程之后的文章将会细讲。

有些地方说明还是有些乱,文章有不当之处,欢迎指正~

参考文档

www.cnblogs.com/wy123/p/836…
www.jianshu.com/p/4bcfffb27…
dev.mysql.com/doc/refman/…
time.geekbang.org/column/arti…
www.cnblogs.com/f-ck-need-u…
segmentfault.com/a/119000000…