在介绍binlog和redolog之前,有必要先简单介绍一下MySQL的逻辑架构。总体上来说,MySQL可以分为server层和engine层两部分,如下图所示:
image
其中server层包括连接池、查询缓存、分析器、优化器等部分,MySQL的大多数核心服务都在这一层,而engine层就是其插件式的存储引擎,主要负责数据的存储和读取。
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:
我们可以通过这条语句来查看MySQL当前的binlog格式:
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;
image
查看当前正在写入的binlog文件:
show master status;
image
查看binlog文件内容:
show binlog events in 'mysql-bin.000006';
image
可以看到,我们执行的insert语句被包裹在一个事务当中,同时binlog原原本本记录了我们的SQL语句。除此之外,我们还发现了另外一些东西:
SET@@SESSION.GTID_NEXT='ANONYMOUS'
主要用于在主备复制时,将主库的gtid集合同步到备库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如下:
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一下就知道了。
image
好,现在切到该目录下执行命令,重点关注红框中的内容。不难发现,与statement模式记录完整SQL语句不通,在row模式下,binlog记录的表中每个字段的值。
image
1.5binlog内容 —— mixed格式
前面提到,在mixed模式下,MySQL默认仍然采用statement格式进行记录,但是一旦它判断可能会有数据不一致的情况发生,则会采用row格式来记录,大家可以自行进行试验查看。
在binlog日志文件目录下,我们还发现了这两个文件:
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
本文从几个方面简单介绍了一下binlog和redo log,现在简单总结一下两者的不同点:
功能不同,binlog主要用于归档,而redo log主要用于崩溃恢复
内容不同,binlog是逻辑日志,而redo log是物理日志
写入时机不同,binlog是server层记录的,所有存储引擎可共享,而redo log是InnoDB引擎特有的
写入方式不同,binlog容量无限,追加写入,而redo log容量有限,循环写入