暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL 基础技术(三)—— MySQL 保证数据不丢失的机制

巴韭特锁螺丝 2022-09-17
133

一、引子

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

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

两阶段提交

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

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

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


二、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 cache
page cache
是 OS 对磁盘IO的缓存。

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

fsync:

将数据持久化到磁盘。

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

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

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
+ fsync
disk
= 1每次事务提交时,都将所有 redo log
fsync
到磁盘。(最安全)
= 2每次事务提交时,都将 redo log
write
page 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 log
    buffer
    中。
    事务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 log
    binlog
    fsync
    成功,但 commit
    失败。
    MySQL
    重启后,发现有完整的binlog
    redo log
    ,继续 commit

    数据成功写入MySQL

    版权声明:本文内容来自简书>作者 : 齐舞647,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
    原文链接:https://www.jianshu.com/p/c5754a4edcfa
    如有涉及到侵权,将立即予以删除处理。
    在此特别鸣谢:简书博主>齐舞647的创作。
    此篇文章所有版权归原作者所有,与本公众号无关,商业转载请联系作者获得授权,非商业转载请注明出处。
    文章转载自巴韭特锁螺丝,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论