[转]一文带你看懂binlog和redo log

https://www.jianshu.com/p/907f9002442e

一文带你看懂binlog和redo log

 

在介绍binlog和redolog之前,有必要先简单介绍一下MySQL的逻辑架构。总体上来说,MySQL可以分为server层和engine层两部分,如下图所示:

[转]一文带你看懂binlog和redo log_第1张图片

image

其中server层包括连接池、查询缓存、分析器、优化器等部分,MySQL的大多数核心服务都在这一层,而engine层就是其插件式的存储引擎,主要负责数据的存储和读取。

1.binlog

1.1binlog作用

我们今天要讲的binlog就是server层产生的日志,因此你知道,不管你使用的是哪一种存储引擎,都会产生binlog。那问题来了,binlog有什么用呢?

要知道它能「做什么」,需要先知道它「是什么」。简单来说,binlog其实就是记录了MySQL对数据库执行更改的所有操作,因此很显然,它可以用来做数据归档和数据恢复。

1.2binlog格式

在MySQL5.1之前,所有的binlog都是基于SQL语句级别的。但是应用这种格式的binlog进行数据恢复时,如果SQL语句带有rand或uuid等函数,可能导致恢复出来的数据与原始数据不一致。因此从5.1版本开始,MySQL引入了binlog_format参数,该参数有三种可选值:statement、row和mixed:

  • statement就是之前的格式,基于SQL语句来记录
  • row记录的则是行的更改情况,可以避免之前提到的数据不一致的问题
  • 但是row格式有一个不好的地方就是当修改的行数很多时,生成的binlog占用很大的空间,占用大量空间的同时还会耗费大量IO资源,因此MySQL又提供了一种折中的方案——mixed。在mixed模式下,MySQL默认仍然采用statement格式进行记录,但是一旦它判断可能会有数据不一致的情况发生,则会采用row格式来记录

我们可以通过这条语句来查看MySQL当前的binlog格式:

[转]一文带你看懂binlog和redo log_第2张图片

image

1.3binlog内容 —— statement格式

为了查看binlog的具体内容,我们先创建一张表并对它进行初始化:

CREATE TABLE `t` (
  `id` int(10) NOT NULL auto_increment,
  `a` int(10) DEFAULT NULL,
  `created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

insert into t values(null, 1,'2019-05-01');
insert into t values(null, 2,'2019-05-02');
insert into t values(null, 3,'2019-05-03');

查看当前binlog文件列表:

show master logs;

[转]一文带你看懂binlog和redo log_第3张图片

image

查看当前正在写入的binlog文件:

show master status;

[转]一文带你看懂binlog和redo log_第4张图片

image

查看binlog文件内容:

show binlog events in 'mysql-bin.000006';

[转]一文带你看懂binlog和redo log_第5张图片

image

可以看到,我们执行的insert语句被包裹在一个事务当中,同时binlog原原本本记录了我们的SQL语句。除此之外,我们还发现了另外一些东西:

  • 第一行的 SET@@SESSION.GTID_NEXT='ANONYMOUS'主要用于在主备复制时,将主库的gtid集合同步到备库
  • 第三行的INSERT_ID=3表示插入该行时的自增id=3
  • 第四行在我们的原始SQL语句之前的多了一句use test;这可以保证我们的SQL语句只会在test库执行
  • 第五行 COMMIT/* xid=1557 */中的xid有两个作用:其一:通过有无xid可以判断一个事务的binlog是否完整;其二:redo log中也有xid,通过这个字段可以将binlog和redo log关联起来

1.4binlog内容 —— row格式

执行以下语句将binlog格式切换为row,看看row格式下的binlog有何不同:

set session binlog_format = 'row';

插入一条新数据:

insert into t values (null, 4, '2019-05-04');

查看binlog如下:

[转]一文带你看懂binlog和redo log_第6张图片

image

可以发现,变化在于第3行和第4行,Intvar和Query两个事件变成了Tablemap和Writerows。但是从这些信息中我们只能知道该事务对表test.t做了插入操作,确并不知道插入的具体数据是什么。

还好我们有mysqlbinlog工具,借助它我们可以一窥究竟。

这里有一点需要说明的是,mysqlbinlog不是MySQL数据库的语法,而只是客户端提供的一个工具,因此不需要登录数据库!!!不需要!!!说来惭愧,这个问题困扰了我好久,怎么就一直提示我语法错误呢?o(╯□╰)o

image

另外执行mysqlbinlog命令必须指定binlog文件的具体路径,笔者使用的是5.7版本,在该版本中,binlog存储路径的默认配置为log-bin=mysql-bin。可是mysql-bin具体哪个路径呢?这个也困扰了我一段时间,其实很简单,find一下就知道了。

[转]一文带你看懂binlog和redo log_第7张图片

image

好,现在切到该目录下执行命令,重点关注红框中的内容。不难发现,与statement模式记录完整SQL语句不通,在row模式下,binlog记录的表中每个字段的值。

[转]一文带你看懂binlog和redo log_第8张图片

image

1.5binlog内容 —— mixed格式

前面提到,在mixed模式下,MySQL默认仍然采用statement格式进行记录,但是一旦它判断可能会有数据不一致的情况发生,则会采用row格式来记录,大家可以自行进行试验查看。

2.redo log

在binlog日志文件目录下,我们还发现了这两个文件:

[转]一文带你看懂binlog和redo log_第9张图片

image

事实上这就是我们接下来要讲的redo log,也就是重做日志,它是InnoDB引擎特有的,记录了InnoDB引擎下的事务日志。

2.1redo log作用

同样,我们首先要搞明白的是,已经有binlog了,为什么还需要redo log。

因为两者分工不同。binlog主要用来做数据归档,但是它并不具备崩溃恢复的能力,也就是说如果你的系统突然崩溃,重启后可能会有部分数据丢失,而redo log的存在则可以完美解决这个问题。

2.2redo log构成

默认情况下,每个InnoDB引擎至少有一个重做日志组,每个组下至少有两个重做日志文件,例如上文提到的iblogfile0和iblogfile1。重做日志组中的每个日志文件大小一致且循环写入,也就是说先写iblogfile0,写满了之后写iblogfile1,一旦iblogfile1也写满了,则继续写iblogfile0。显然,如果没有任何保护措施,这种机制会导致之前写入ib_logfile0的内容被覆盖。因此一旦redo log写满,MySQL将不得不停下所有更新操作来刷脏页,这也是我们在为什么你的SQL执行很慢中提到的一点。

2.3redo log内容

binlog有三种格式,并且每种格式我们都可以具体查看其内容,那么redo log的内容怎么查看呢?

目前好像并没有什么办法可以以人类可以理解的方式查看redo log,原因在于与binlog记录的是逻辑日志不同,redo log记录的是对数据页更改的物理日志,比如类似「将第8页、第1行、第6个位置改成666」这种,下图是我用hexdump查看ib_logfile0的结果,其中红框标出来的部分是插入一条数据后新增的日志文件。

image

3.总结

本文从几个方面简单介绍了一下binlog和redo log,现在简单总结一下两者的不同点:

  • 功能不同,binlog主要用于归档,而redo log主要用于崩溃恢复

  • 内容不同,binlog是逻辑日志,而redo log是物理日志

  • 写入时机不同,binlog是server层记录的,所有存储引擎可共享,而redo log是InnoDB引擎特有的

  • 写入方式不同,binlog容量无限,追加写入,而redo log容量有限,循环写入

你可能感兴趣的:(数据库,mysql)