MySQL 基础技术(三)—— MySQL 如何保证数据不丢失?

之前,有一年多的工作客户端领域的工作经验。
后来,也在字节做了一年多的后端业务。
现在希望做一些 MySQL 总结,丰富一下自己在后端领域的积累。
目录如下:
MySQL 基础技术(一) —— MySQL 是如何查询的?
MySQL 基础技术(二) —— MySQL 是如何更新的?
MySQL 基础技术(三)—— MySQL 如何保证数据不丢失?
MySQL 基础技术(四)—— MySQL 如何保证高可用?


一、引子

上篇:《MySQL 是如何更新的?》中,我们介绍了MySQL的两个重要的日志:binlogredo log

其中,binlog 对应 MySQLServer 层的逻辑日志。
redo log 对应 MySQLInndoDB 引擎下的 Engine 层物理日志。
为了保证数据的一致性, MySQL 用一个事务将两个日志的写逻辑的一致性。(即“两阶段提交”)

两阶段提交

MySQL 的两阶段提交 + WAL技术(Write-Ahead Logging,先写日志再写盘),这两个结合在一起保证了数据不会丢失。

即:只要 redo logbinlog 持久化到磁盘,即使 MySQL 异常,重启后数据依然可以恢复。
那么,redo logbinlog 的写入流程具体是怎样的?具体是怎么保证的?

本篇,让我们一起详细了解下 redo logbinlog 的写入流程。


二、binlog 写入流程

首先,我们先了解下MySQL Server 层日志 —— binlog 的写入具体流程。

其实,binlog 的写入流程比较简单:

  1. 先把 binlog 日志写到 binlog cache
  2. 事务提交时,将 binlog cache 写入 binlog 文件。

系统给每个线程的 binlog cache 分配了一片内存,大小为 binlog_cache_size
如果超过这个大小,就会把cache暂存到磁盘的临时文件(tmp files)中。

这个很好理解,binlog cache 由内存和临时文件组件。
因为内存是有限的,在事务完成前不能直接写入最终日志文件,因此只能先临时写到临时文件(tmp files)中。

binlog写入流程

我们可以看到,每个线程都有自己的 binlog cache。但是,都共用同一份binlog文件。

write:

把日志写入文件系统内核的 page cachepage cache是 OS 对磁盘IO的缓存。

适合小文件传输。因为大文件传输 page cache 命中率低,这时不仅没有起到缓存作用,反而增加了一次数据从磁盘 buffer 到 内核 page cache 的开销。

fsync:

将数据持久化到磁盘。

fsync 才占磁盘的 IOPS(Input/Output Operations Per Second)

MySQL 有一个参数:sync_binlog ,用来控制 writefsync 的时机。
可以根据业务场景的需要,来具体调整。

sync_binlog 含义
等于 0 每次事务提交只write,不fsync。(不推荐)
等于 1 每次事务提交不仅write,都会执行 fsync。(这个配置是最安全的,不会丢binlog日志)
等于 N 每次提交事务都write,累积N个事务后,一起fsync。(性能好,但是异常重启会丢N个事务的binlog日志)

三、redo log 写入流程

了解了 binlog 的写入流程,下面我们来看看 redo log 的写入流程。

  1. 首先,写入 redo log buffer
  2. 其次,写入(write)文件系统的 page cache
  3. 最后,持久化(fsync)到磁盘 disk

是不是感觉和 binlog 有点类似?

但实际上他们之间还是有很大差异的,下面我们了解下他们之间的差异。

InnoDB 提供了 innodb_flush_log_at_trx_commit 参数来控制 redo log 写入流程。

innodb_flush_log_at_trx_commit 含义*
= 0 每次事务提交时,redo log 只会留在 redo log buffer。(风险大,等待每秒 write + fsyncdisk
= 1 每次事务提交时,都将所有 redo log fsync到磁盘。(最安全)
= 2 每次事务提交时,都将 redo log writepage cache

每秒刷盘机制

InnoDB 有一个后台线程,每隔1秒,就会把 redo log buffer中的日志,调用 write 写到 page cache,然后 fsync 持久化到磁盘。

需要注意的是,事务执行中的 redo log 也是存在于 redo log buffer 的,也会被一起持久化到磁盘。(也就是说,一个还没有提交事务的 redo log,也可能已经被持久化到磁盘了)

强制刷盘

其实,不光每秒刷盘会提前持久化 redo log 到磁盘。

  • redo log buffer 到达 innodb_log_buffer_size (缓冲池大小,默认是8MB)一半的时候,会主动触发 write 到文件系统的 page cache
  • 并行事务提交,顺带将其他事务的 redo log buffer 持久化到磁盘。
    举例:
    事务A 执行到一半,写入了部分 redo logbuffer 中。
    事务B 完成,进行提交。
    如果innodb_flush_log_at_trx_commit设置为1,代表每次提交都会全部fsync到磁盘。这时候,事务A的 redo log 也有部分已经持久化了。

这时候,有同学可能会问:
两阶段提交,不是最后一步才会 fsync 到磁盘上么?为什么提前持久化了呢?会有啥影响吗?

首先,prepare 阶段提前fsync到磁盘并没有问题。
因为 binlog 还没有 ready。还没到最后的 commit,并没有实际执行。
其次,磁盘IOPS是有瓶颈的。MySQL这样设计可以降低磁盘IO,提高性能。

四、双“1”配置,最安全

只有在 sync_binlog 和 innodb_flush_log_at_trx_commit 都等于1的情况下,才能保证数据不丢失。

  • 写 redo log 时,每次事务提交时,都将所有redo log fsync到磁盘
  • 写 binlog 时,每次事务提交时,binlog 都会执行 fsync到磁盘。

虽然,双1配置可以保证数据安全性。但是往往越安全,性能就会不如意。
在某些性能要求比较高的场景下,往往会故意打破双1配置。
(虽然在 MySQL异常时,会丢一些数据。但在大量数据的基数下,风险依然可控。)

问:为什么双“1”配置就一定是最安全的?能证明么?
答:别着急,等看完“五、真正的两阶段提交”,咱就明白了。

五、真正的两阶段提交

两阶段提交

之前,给大家介绍两阶段提交时,我画了这张图,比较好理解。
但其实由于MySQL redo log 组提交优化,真正的两阶段提交如下图:

真正的两阶段提交

MySQL这样设计的好处是,可以组提交,交叉fsync
一组 fsync收集的write越多, 对应的磁盘的IO越少,提高MySQL性能。

因此,WAL的优势在于:

  1. redo log & binlog 都是按顺序写入磁盘的,比随机写磁盘速度快。
  2. 组提交机制,合并fsync。大幅度降低磁盘的IOPS消耗,提高IO性能。

证明数据安全

上图分为五个阶段,这样,我们在双“1”配置下,利用反证法来验证数据安全性。

  1. 如果 MySQL 挂在了 1,2,3 阶段。

这时候,不论redo log 还是 binlog 都还没有 fsync 到磁盘。
因此,掉电导致内存丢失,实际也没写入磁盘,数据一致性。

  1. 如果 MySQL 挂在了第 4 阶段 fsync binlog
    redo log fsync 成功, binlog fsync 失败。
    MySQL重启后,发现有 redo log 的磁盘数据,没有binlog磁盘数据。
    发现是redo log处于prepare阶段,回滚(删除磁盘里的redo log)。

  2. 如果 MySQL 挂在了第 5 阶段 commit
    redo logbinlogfsync 成功,但 commit 失败。
    MySQL重启后,发现有完整的binlogredo log,继续 commit
    数据成功写入MySQL

至此,我们理解了 MySQL 是如何保证数据不丢失的。
下篇,我们会介绍,MySQL是如何保证高可用的。

参考与致谢:
1.《MySQL实战45讲》(林晓斌老师)

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