vlambda博客
学习文章列表

MYSQL从入门到放弃(二)重要的日志模块

上篇文章主要是根据 select 语句的流程简单的介绍了 SQL 的执行流程。

 

今天我们就来说一说, SQL 执行过程中还会涉及到的两个重要的日志模块,redo log 与 binlog。

redo log(重做日志)

当某一行记录需要进行更新时,InnoDB 引擎就会先把记录写到 redo log 中,并更新内存, 这时候就更新完成了,再在适当的时刻,InnoDB引擎会把这个操作记录更新到磁盘里。

 

InnoDB的redo log 是有固定大小的,那这么说如果redo log 写满了,怎么办呢?那就是redo log 会先清理掉一部分,这个被清理掉的部分先写进磁盘中。

 

 

write pos 是当前记录的位置,一边写一遍下移。check point 就是当前要清理的位置,也是往后推移的,清理的记录就要先写进数据文件里。

 

有了 redo log ,InnoDB 就会保证数据库异常重启后,之前提交的记录不会丢失,这种能力就叫做 crash - safe。

binlog(归档日志)

之前说过 mysql 分为两个模块server层和存储引擎层 ,那么binlog就是 server 层的日志。

 

这时候就会有疑惑了,为什么 MYSQL 会有两个日志呢?其实是这样的,最早的版本 MYSQL默认的存储引擎是MyISAM,但是吧,它并没有crash - safe 的能力,binlog 只能用于归档啊。所以它就来了。

 

这两个日志大体上有三种不同:

1.redo log 是存储引擎特有的,binlog 是server层实现的。

2.redo log 是物理日志,主要记录了在某个数据页上修改了什么,而binlog 是逻辑日志,记录了这个语句的原始逻辑,即给哪一行的哪个字段做了什么操作。

3.redo log 是循环写的,固定的空间,binlog 是追加写的,即写完固定大小之后,我在翻一页,再继续写,不会覆盖之前写的。

 

举个例子:

update user set age=age+1 where ID=7;

 

我们简单来说一下这个SQL的执行流程:

1.执行器先找到引擎取ID=7这一行,ID是主键,引擎直接用树搜索找到这一行,如果ID=7这一行本来就存在于数据页中,那么直接返回给执行器,如果不存在,就去磁盘读入内存,再返回。

2.执行器拿到引擎给的数据,在这个数据上 age + 1,得到了一行新数据,再把这行新数据调用接口写入。

3.引擎将这行数据更新到内存中,同时将这条操作记录到redo log 中,此时redo log 处于 perpare 状态了。然后告知执行器说:我朋友说他好了,随时可以提交。

4.执行器生成这个操作的binlog ,将这个binlog 写入磁盘。

5.执行器调用引擎的提交事务接口,把给给写入的binlog 改成提交(commit)状态,更新完成。

 

仔细一看,咦?这怎么有两个提交呢(perpare 和 commit)?这就是我们将要说到的“两阶段提交”。为什么要存在这个“两阶段提交”呢?这可能就要说到了,如果不小心删库了,除了跑路还能干什么,当然,这个会在后续的文章里进行详细讲解。

 

由于这两个日志都是独立的逻辑,如果不用两阶段提交可能就会导致从 crash - safe 中恢复回来的数据和之前的数据不一致的问题。除了 crash - safe 之外还有别的情况么,当然有了, 当你想要扩容的时候,也就是在备库上增加系统的读能力的时候。这个情况可能会导致你的主备数据不一致的问题。

 

还有一点就是 两阶段提交,跨系统维度维持数据一致性时的常用的一个方案。