MySQL 里有两个日记,即:重做日记(redo log)和归档日记(binlog)。(引荐课程:MySQL教程)
个中,binlog 能够给备库运用,也能够保存起来用于恢复数据库汗青数据。它是实如今 server 层的,一切引擎能够共用。redo log 是 InnoDB 特有的日记,用来支撑 crash-safe 才能。
你肯定听过 MySQL 事件的两阶段提交,指的就是在事件提交的时候,分红 prepare 和 commit 两个阶段。
如图 1 所示为一个事件的实行流程,你在末了三步能够看到,redo log 先 prepare 完成,再写 binlog,末了才进入 redo log commit 阶段。
图 1 两阶段提交示意图
这里,我要先和你诠释一个误解式的题目:这个图不就是一个 update 语句的实行流程吗,怎样还会挪用 commit 语句?
通常状况下,你会发作这个疑问的缘由,在于把两个“commit”的观点殽杂了:
题目中的“commit 语句”,是指 MySQL 语法中,用于提交一个事件的敕令。平常跟 begin/start transaction 配对运用。
而我们图中用到的这个“commit 步骤”,指的是事件提交过程当中的一个小步骤,也是末了一步。当这个步骤实行完成后,这个事件就提交完成了。
“commit 语句”实行的时候,会包含“commit 步骤”。
而我们这个例子内里,没有显式地开启事件,因而这个 update 语句本身就是一个事件,在实行完成后提交事件时,就会用到这个“commit 步骤”。
接下来,我们就一同剖析一下在两阶段提交的差别时候,MySQL 非常重启会涌现什么征象。
假如在图中时候 A 的处所,也就是写入 redo log 处于 prepare 阶段今后、写 binlog 之前,发作了崩溃(crash),由于此时 binlog 还没写,redo log 也还没提交,所以崩溃恢复的时候,这个事件会回滚。这时候,binlog 还没写,所以也不会传到备库。到这里,我们都能够明白。
而我们明白会涌现题目的处所,主要集合在时候 B,也就是 binlog 写完,redo log 还没 commit 前发作 crash,那崩溃恢复的时候 MySQL 会怎样处置惩罚?
我们先来看一下崩溃恢复时的推断划定规矩。
1、假如 redo log 内里的事件是完全的,也就是已有了 commit 标识,则直接提交;
2、假如 redo log 内里的事件只要完全的 prepare,则推断对应的事件 binlog 是不是存在并完全:
a.假如是,则提交事件;
b.不然,回滚事件。
这里,时候 B 发作 crash 对应的就是 2(a) 的状况,崩溃恢复过程当中事件会被提交。
如今,我们就针对两阶段提交再继承延展一下。
题目 1:MySQL 怎样晓得 binlog 是完全的?
回覆:一个事件的 binlog 是有完全花样的:
假如碰到既有 prepare、又有 commit 的 redo log,就直接提交;
假如碰到只要 parepare、而没有 commit 的 redo log,就拿着 XID 去 binlog 找对应的事件。
题目 3:处于 prepare 阶段的 redo log 加上完全 binlog,重启就可以恢复,MySQL 为何要这么设想?
回覆:实在,这个题目照样跟我们在反证法中说到的数据与备份的一致性有关。在时候 B,也就是 binlog 写完今后 MySQL 发作崩溃,这时候 binlog 已写入了,今后就会被从库(或许用这个 binlog 恢复出来的库)运用。
所以,在主库上也要提交这个事件。采纳这个战略,主库和备库的数据就保证了一致性。
题目 4:假如如许的话,为何还要两阶段提交呢?痛快先 redo log 写完,再写 binlog。崩溃恢复的时候,必须得两个日记都完全才能够。是不是是一样的逻辑?
回覆:实在,两阶段提交是典范的分布式体系题目,并非 MySQL 独占的。
假如必需要举一个场景,来申明这么做的必要性的话,那就是事件的耐久性题目。
关于 InnoDB 引擎来说,假如 redo log 提交完成了,事件就不能回滚(假如这还许可回滚,就能够覆盖掉别的事件的更新)。而假如 redo log 直接提交,然后 binlog 写入的时候失利,InnoDB 又回滚不了,数据和 binlog 日记又不一致了。
两阶段提交就是为了给一切人一个时机,当每个人都说“我 ok”的时候,再一同提交。
题目 5:不引入两个日记,也就没有两阶段提交的必要了。只用 binlog 来支撑崩溃恢复,又能支撑归档,不就可以够了?
回覆:我把这个题目再翻译一下的话,是说只保存 binlog,然后能够把提交流程改成如许:... -> “数据更新到内存” -> “写 binlog” -> “提交事件”,是不是是也能够供应崩溃恢复的才能?
答案是不能够。
假如说汗青缘由的话,那就是 InnoDB 并非 MySQL 的原生存储引擎。MySQL 的原生引擎是 MyISAM,设想之初就有没有支撑崩溃恢复。
InnoDB 在作为 MySQL 的插件到场 MySQL 引擎家属之前,就已是一个供应了崩溃恢复和事件支撑的引擎了。
InnoDB 接入了 MySQL 后,发明既然 binlog 没有崩溃恢复的才能,那就用 InnoDB 原有的 redo log 好了。
而假如说完成上的缘由的话,就有许多了。就根据题目中说的,只用 binlog 来完成崩溃恢复的流程,我画了一张示意图,这里就没有 redo log 了。
图 2 只用 binlog 支撑崩溃恢复
如许的流程下,binlog 照样不能支撑崩溃恢复的。我说一个不支撑的点吧:binlog 没有才能恢复“数据页”。
假如在图中标的位置,也就是 binlog2 写完了,然则全部事件还没有 commit 的时候,MySQL 发作了 crash。
重启后,引擎内部事件 2 会回滚,然后运用 binlog2 能够补返来;然则关于事件 1 来说,体系已以为提交完成了,不会再运用一次 binlog1。
然则,InnoDB 引擎运用的是 WAL 手艺,实行事件的时候,写完内存和日记,事件就算完成了。假如今后崩溃,要依赖于日记来恢复数据页。
也就是说在图中这个位置发作崩溃的话,事件 1 也是能够丧失了的,而且是数据页级的丧失。此时,binlog 内里并没有纪录数据页的更新细节,是补不返来的。
你假如要说,那我优化一下 binlog 的内容,让它来纪录数据页的变动能够吗?能够,但这实在就是又做了一个 redo log 出来。
所以,最少如今的 binlog 才能,还不能支撑崩溃恢复。
题目 6:那能不能反过来,只用 redo log,不要 binlog?
回覆:假如只从崩溃恢复的角度来说是能够的。你能够把 binlog 关掉,如许就没有两阶段提交了,但体系依然是 crash-safe 的。
然则,假如你相识一下业界各个公司的运用场景的话,就会发如今正式的生产库上,binlog 都是开着的。由于 binlog 有着 redo log 没法替换的功用。
一个是归档。redo log 是轮回写,写到末端是要回到开首继承写的。如许汗青日记没法保存,redo log 也就起不到归档的作用。
一个就是 MySQL 体系依赖于 binlog。binlog 作为 MySQL 一开始就有的功用,被用在了许多处所。个中,MySQL 体系高可用的基本,就是 binlog 复制。
另有许多公司有异构体系(比方一些数据剖析体系),这些体系就靠消耗 MySQL 的 binlog 来更新本身的数据。关掉 binlog 的话,这些下流体系就没法输入了。
总之,由于如今包含 MySQL 高可用在内的许多体系机制都依赖于 binlog,所以“鸠占鹊巢” redo log 还做不到。你看,生长生态是何等主要。
末了,引荐你关注丁奇的《MySQL 实战 45 讲》专栏。在专栏里,丁奇会帮你梳理出进修 MySQL 的主线学问,比方事件、索引、锁等,还会就开辟过程当中常常碰到的具体题目和你剖析议论,而且帮你明白题目背地的实质。你会收成 MySQL 核心手艺详解与道理申明和 36 个 MySQL 罕见痛点题目剖析。
statement 花样的 binlog,末了会有 COMMIT;
row 花样的 binlog,末了会有一个 XID event。
别的,在 MySQL 5.6.2 版本今后,还引入了 binlog-checksum 参数,用来考证 binlog 内容的正确性。关于 binlog 日记由于磁盘缘由,能够会在日记中心失足的状况,MySQL 能够经由过程校验 checksum 的效果来发明。所以,MySQL 照样有方法考证事件 binlog 的完全性的。
题目 2:redo log 和 binlog 是怎样关联起来的?
回覆:它们有一个配合的数据字段,叫 XID。崩溃恢复的时候,会按递次扫描 redo log:
以上就是MySQL中罕见的日记题目引见的细致内容,更多请关注ki4网别的相干文章!