mysql的断电恢复能力

概述

这段时间对mysql数据库事务的acid做了一些深入的研究,理解了如何在异常情况下保证事务的acid。而最严重的异常情况莫过于断电,随时都有可能发生且发生时不会有任何保存的机会,所以就想以事务处理的各个阶段发生断电的情况下mysql如何保证acid为切入点总结一下这段时间所学到的东西。
本文将重点介绍commit命令执行的各个阶段,mysql是如何进行断电恢复的。

mysql的page、日志和buffer介绍

page

mysql的page与文件系统的block类似,是mysql自己定义的读取和写入磁盘的最小单位,其目的是为了充分的利用磁盘的顺序访问速度快的优势。一般是磁盘扇区的4~16倍。

logs

  • undolog。即 mvcc 历史快照,记录的是某行过去的某个版本,用于帮助事务回滚及 MVCC 的功能。存储在表空间,以 transaction 为维度记录,且记录了 transaction 状态 ,可用于 crash 恢复时提取未提交的事务。可以理解成一张特殊的表,也会用到 buffer pool 。
  • redolog。可以理解为内存数据的WAL(write-ahead-log),用来恢复未flush到disk的page数据。记录的是对页的二进制级别的修改操作,比如某个偏移写入'aa'记录。** 一般存储在单独的redo log文件中,数据库全局的。另外要注意的是, undolog 的写入也会生成对应的 redo log 。**
  • binlog。即我们常说的二进制日志,主要用于主从复制。

buffer

  • buffer pool。即 mysql page 的 buffer 。使用 lru 来管理。
  • doublewrite buffer。在 flush page 到磁盘之前,会先将 page 写入这里,为了防止 page flush 到一半时断电造成的磁盘 page 数据不完整的问题。存储介质虽为文件,但充分利用顺序写,所以很快。
  • log buffer。即 redolog 的内存 buffer 。 用于降低 redolog 对于写入速度的影响。

除了这些还有 change buffer 等,不影响接下来的内容介绍,故不在此处展开讨论。

mysql写入过程简介

commit 之前

先说说 commit 命令之前,写入操作对应的过程。 此时所有的写入操作都会通过 undolog 的支持,同时保留写入之前的版本和写入之后的版本,而这里对表数据和 undolog 的修改并不会直接写入到磁盘中,而是写入 buffer pool 中,同时生成相应的 redolog 。而此时的 redolog 存放在 log buffer 中,这样做的目的是为了减少 redolog 对写入性能的影响。想象一下,如果每次写入产生的 redolog 都写入磁盘,即使是顺序写入,也会造成不小的影响。所以,如果一个 transaction 中包含大量的写入操作,最好将 log buffer 调大一些,避免不必要的磁盘 io 。
下面说说 commit 的执行过程。由于在生产环境中,绝大多数 mysql 实例都会开启 binlog ,因此我们主要介绍开启 binlog 时 commit 的实行过程。

commit 执行过程

在开启 binlog 的情况下, mysql 使用 2PC 来执行 commit 过程,具体步骤如下:

  • 阶段1:将 undolog 中的 transaction 状态改为 prepared ,并生成相应的生成 redolog ,然后 flush log buffer 。
  • 阶段2:将 transaction 写入 binlog ,然后告诉底层存储引擎将 undolog 中的 transaction 状态改为 commited 并生成 redo log 。只要写入binlog成功,就可以认为事务写入成功。

另外需要注意的是,此时 mysql 使用 xid 来标识该事务。

断电恢复过程

完成了 prepare 阶段,写入 binlog 之前断电

这种情况下, mysql 重新启动时,会从 redolog 中读出未 flush 到磁盘中的 page —— buffer pool 。然后从 redolog 重建这些内存中的 page ,以恢复断电之前内存的状态。之后,mysql检测到该事务并未提交,因此主动执行事务的回滚操作。

flush buffer pool 时断电

即 flush page 的时候。此时造成 page 一部分数据写入磁盘,另一部分数据未写入磁盘。这时无法从 redo log 恢复异常 page 。原因是:之前提到 redo log 保存的page的修改记录,即从原 page 到新 page 的 patch ,而此时原 page 已经丢失(因为 page 的一部分数据已经写入磁盘),所以无法从 redo log 恢复。这时就要用到 double write buffer 了。每次 flush page 之前,都会先将 page flush 到一个 double write buffer ,如果在真正 flush page 的时候出现异常,则可以从 double write buffer 恢复这个 page 。

flush log buffer 时断电

即 redolog 的flush。由于 redolog 的 flush 是以扇区为单位进行 flush 的,而扇区的写入是原子性的(当代的大部分硬盘都有这个能力),因此不会造成部分写入、部分未写入的情况。

写完 binlog 后断电

上面说到,写入binlog时,便可认为事务提交成功,就可以保证acid中的d。此时如果断电,mysql在启动会执行如下过程:

  1. 先从binlog中筛选出所有xid并创建hash_list
  2. 然后从存储引擎(如innodb)中选出prepared状态的transaction的xid列表list。一般是从rollback segments(rseg) —— undo log ——中提取xid列表,然后在选出prepared状态的。
  3. 遍历list的xid,如果xid在hash_list中则commit,否则rollback。

写入 binlog 时断电

binlog 的写入也是没有 double write buffer 保护的,那么在写入 binlog 的过程中如果发生了断电, mysql 是如何恢复的呢。如上面介绍的写入 binlog 后断电恢复过程所示, mysql 会从 binlog 中选出所有的 xid 并创建恢复列表,不过在遍历 binlog 的过程中, mysql 同时也会寻找 last valid position ,并将这个 position 之后的内容都截取掉。因此,如果某个 transaction 写入 binlog 的过程中断电,并且有一部分未成功写入,则该 transaction 在 mysql 重启时会被回滚。

相关配置

这些配置是mysql5.7之后的默认配置:

  • sync_binlog=1
  • innodb_support_xa=ON
  • innodb_flush_log_at_trx_commit=1。用于控制 log buffer 的刷新时机。

参考资料

《Mysql技术内幕》
https://dev.mysql.com/doc/refman/5.7/en/glossary.html
mysql5.7源码——sql/binlog.cc

作者: Normal Cock
链接: https://normal-cock.github.io/passages/mysql-power-off-and-recovery/
来源: normal-cock.github.io
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容