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 之外还有别的情况么,当然有了, 当你想要扩容的时候,也就是在备库上增加系统的读能力的时候。这个情况可能会导致你的主备数据不一致的问题。
还有一点就是 两阶段提交,跨系统维度维持数据一致性时的常用的一个方案。