【MySQL】双写、重做日志对宕机时脏页数据落盘的作用的疑问及浅析

众所周知,双写机制、重做日志文件是mysql的InnoDB引擎的几个重要特性之二。其中两者的作用都是什么,很多文章都有分析,如,双写机制(Double Write)是mysql在crash后恢复的机制,而重做日志文件(Redo Log File)也是mysql崩溃恢复机制的一部分。但是,这两者是如何保证mysql能够正确恢复数据的呢?对此,我在看书查证和思考过程中,产生了很多的疑问,也有一些收获,写在下面。

一,介绍双写机制、重做日志文件

首先,我先介绍或者说概括一下双写机制,和重做日志文件。在《MySQL技术内幕 InnoDB技术引擎》[1]一书中,双写机制部分介绍原文如下:

如果说Insert Buffer带给InnoDB存储引擎的是性能上的提升,那么doublewrite(两次写)带给InnoDB存储引擎的是数据页的可靠性。
当发生数据库宕机时,可能InnoDB存储引擎正在写入某个页到表中,而这个页只写了一部分,比如16kb的页,只写了前4kb,之后就发生了宕机,这种情况被成为部分写失效(partial page write)。在InnoDB存储引擎未使用doublewrte技术前,曾经出现过因为部分写失效而导致数据丢失的情况。
有经验的DBA也许会想,如果发生写失效,可以通过重做日志进行恢复。这是一个办法,但是必须清楚的意识到,重做日志中记录的是对页的物理操作,如偏移量800,写’aaa’记录。如果这个页本身已经发生了损坏,再对其进行重做是没有意义的。这就是说,在应用(apply)重做日志之前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是doublewrite。在InnoDB存储引擎中doublewrite的体系架构如图2-5所示。
doublewrite由2部分组成,一部分是内存中的doublewrite buffer,大小为2MB,另一部分是物理磁盘上共享表空间中连续的128个页,即2个区(extent),大小同样为2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先复制到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次,每次1MB顺序的写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。在这个过程中,因为doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成doublewrite页的写入后,再将doublewrite buffer中的页写入各个表空间文件中,此时的写入则是离散的。

重做日志部分原文如下:

在默认情况下,在InnoDB存储引擎的数据目录下会有2个名为ib_logfile0和ib_logfile1的文件。在mysql官方手册中将其称为InnoDB存储引擎的日志文件,不过准确的定义应该是重做日志文件(redo log file)。为什么强调是重做日志文件呢?因为重做日志文件对于InnoDB存储引擎至关重要,它们记录了对于innoDB存储引擎的事务日志。
当实例或介质失败(media failure)时,重做日志文件就能派上用场。例如,数据库由于所在主机掉电导致实例失败,InnoDB存储引擎会使用重做日志恢复到掉电前的时刻,以此来保证数据的完整性。
每个InnoDB存储引擎至少有1个重做日志文件组(group),每个文件组下至少有2个重做日志文件,如默认的ib_logfile0和ib_logfile1。为了得到更高的可靠性,用户可以设置多个的镜像日志组(mirrored log groups),将不同的文件组放在不同的磁盘上,以此提高重做日志的高可用性。在日志组中每个重做日志文件的大小一致,并以循环写入的方式运行。InnoDB存储引擎先写重做日志文件1,当达到文件的最后时,会切换至重做日志文件2,再当重做日志文件2也被写满时,会再切换到重做日志文件1中。

双写和重做日志不是单独运行的,这两者是结合起来运行的。在文章[4]中,描述了双写机制、重做日志运行的原理

在这里插入图片描述

第一步,master thread会每秒将写操作的重做日志缓冲刷写到redo log中。
第二步,通过memcpy函数将脏页copy到doubewrite buffer(内存)中。
第三步,将doublewrite buffer第一次刷写fsync到磁盘(系统表空间)。
第四步,将doublewrite buffer第二次刷写fsync到磁盘(独立表空间)。

二,问题及思考结果

1,双写机制的作用是什么?
书中[1]写到,双写机制的作用是为了应对部分页写入的情况。实际上,不止是书中写的”16kb的页,只写了前4kb,就发生了宕机“这种情况。在写入的时候,怎么会完完整整的写完一个Linux的页才宕机呢?(32位linux系统支持4k的页[2])

实际上,更可能的是,假设一个16kb的脏页,写入了前4k的页,正在写入第2个4k的linux页,结果断电了。此时导致的必然结果就是第二个页的格式错误。

这种部分页写入的情况,会导致数据的格式错误,无法通过mysql的自检,进而需要双写机制来恢复数据。

因此,你看到书中[1]举的栗子中,mysql在使用双写机制恢复的时候,Info信息是:

InnoDB: Crash recovery may have failed for some .ibd files!
InnoDB: Restoring possible half-written data pages from the doublewrite

也就是说,双写机制的作用,是恢复因为部分页写入导致发生数据格式错误的页。

2,双写机制也需要写入系统表空间的磁盘中,同样的数据,也要第二次写入数据所在的独立表空间的磁盘空间,那有没有可能,在双写机制向系统表空间中写入(第一次写)的时候crash断电呢?

书中[1]写到:
doublewrite由2部分组成,一部分是内存中的doublewrite buffer,大小为2MB,另一部分是物理磁盘上共享表空间中连续的128个页,即2个区(extent),大小同样是2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先复制到内存中的doublewrite buffer,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。在这个过程中,因为doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成doublewrite页的写入后,再将doublewrite buffer中的页写入各个表空间文件中,此时的写入是离散的。

首先,我们需要知道,随机IO和顺序IO在性能上的区别。在《高性能mysql》[3]中,进行了随机IO和顺序IO的对比,在举例中描述”相比之下顺序读可以每秒读500000行——是随机读的5000“倍。这是3个数量级的差别,即使栗子中的情况和实际机器的性能、实际读写的情况有差别,也不会差太多。也就是说,随机IO和顺序IO是有大约三四个数量级上的速度差别的。

双写机制的2次写是连续的,总共为2MB。mysql每秒最多刷新100个脏页到独立表空间中。100个脏页为1600kb,即1.6MB,因此可以说双写机制提供的2MB是够用的。但是问题是这100个脏页可能是随机IO。

假设master thread的写入压力比较大,每秒刷新100个脏页,会第一步先向redo log磁盘文件中写入、第二步将脏页memcpy到内存中的双写buffer中,第三步是将双写buffer fsync到系统表空间的双写文件中,最后,将这100个脏页刷写到独立表空间的磁盘文件中。2MB的数据,第1、3步都是顺序IO,磁盘寻址一次定位到文件后,会顺序写入2MB数据即可,第2步是内存中的复制,只有第4步,是要将100个mysql页随机IO写入磁盘,(一个32位linux系统支持4kb的页,即一个Mysql页包括4个Linux页,但是mysql内部用 内存映射文件,这种都是连续的页)意味着系统需要在磁盘中寻址100次。(怕读者们混乱,linux系统的页举例使用了《MySQL技术内幕》中举例的4kb大小的页,而不是64位系统的8kb页[2])

总之,不难发现,仅以双写机制第一次写入:将数据写入系统表空间,和第二次写入:将数据写入磁盘的独立表空间而言,第一次写入仅需寻址1次,顺序写入2MB数据;而第二次写入,需要最多100次寻址。意味着第一次写入占用的时间仅占总寻址时间的1/(100+1)。因此双写机制在第一次写入时crash的几率是非常小的。(数据的写入时间这里不作讨论,随机IO主要时间在磁盘寻址上)。

至于mysql有没有可能在第一次写入的时候崩溃呢,当然有啦。我很喜欢周sang的那句话,中间件的设计中,很多都是balance,做权衡InnoDB设计的双写机制,以写入磁盘的1/100寻址时间的性能开销,以及这段时间内crash数据无法正确恢复的微小可能,换来可以保证crash崩溃断电这种极端情况发生时,数据错误时能够恢复到正确的格式,以及配合redo log后,InnoDB可以异步写入而不担心脏页数据丢失,无疑是值得的。

3,类似问题2,redo log会不会也在写入的时候crash呢?

有可能,但是可能性很小。

我们看《MySQL技术内幕》[1]中讲述到,
(InnoDB)每秒一次的操作包括:
日志缓冲刷新到磁盘,即使这个事务还没有提交(总是)
合并插入缓冲(可能)
至多刷新100个InnoDB的缓冲池中的脏页到磁盘(可能)
如果当前没有用户活动,则切换到background loop(可能)

日志缓冲指的就是重做日志缓冲(redo log buffer)。此外,引擎会在事务提交时也将日志缓冲刷新到磁盘。

综上可以看出,其实重做日志缓冲会非常勤奋的刷新到redo log中,这样可以保证不会将一次事务的所有刷新磁盘的压力都堆积到一次刷新中。

其次,redo log是顺序IO,会在默认的两个redo log中循环写,一个文件写满了就在另一个文件中写(脏数据写入磁盘后会从redo log中删除)。从问题2中我们讲了,顺序IO就是要比同数据量的随机IO快。

最后[1],InnoDB存储引擎的重做日志文件记录的是关于每个页(page)的更改的物理情况,如偏移量800,写’aaa’记录。这样就保证了每次写操作需要记录的redo log的大小很小。

综上所述,使得redo log的写入很快,远快于redo log记录的写操作在磁盘中写入的时间。

4,假设写入压力很大,mysql每秒100个脏页写入都无法把缓冲池中的脏页刷写完,那么在crash后,仅靠双写的2MB数据无法完全恢复数据,那么要怎么恢复数据呢?
首先需要明确,那个2MB大小的双写文件,不是为了恢复数据用的,它仅仅是为了保证写入时发生crash导致部分页写入,用来恢复发生部分页写入那部分页的正确格式的。至于恢复缓冲池中的脏页数据,是redo log的活儿。

《MySQL技术内幕》[1]中,写到,在InnoDB版本1.2.x之前,redo log总大小不得超过4GB,在1.2.x之后,限制扩大到512GB。

也就是说,即使mysql的写入压力很大,每秒100个脏页的写入都不够,InnoDB的缓冲池中积压了很多旧的写入请求的脏页,还有很多脏页没有写入磁盘,但是它们都已经写入redo log,最多512G,它们这些脏页都可以写入到redo log中。

而新的写入操作,也会每秒的日志缓冲刷写到磁盘的redo log中,最大限度的保存脏页数据。

三,写在最后

其实从这里我个人觉得,双写机制和重做日志文件,是InnoDB引擎能够实现异步IO的关键,它们结合起来最大限度的保证了即使是异步IO,内存中的脏页数据最后也可以落盘,即事务的持久性,并且崩溃不会导致部分页写入。而异步IO,无疑很大的提升了InnoDB的写入性能。

或者更抽象的说,InnoDB在做了一定程度的design and balance后,以微小的性能开销和很小的数据丢失风险,保证了InnoDB的异步IO和、页数据的持久性以及crash时的数据正确性。

在谈双写机制时,离不开重做日志保证数据完整性,在谈重做日志文件时,离不开双写机制保证数据最后写的页不发生部分页写入。

参考文章
[1],MySQL技术内幕 InnoDB技术引擎, 作者:姜承尧
[2],Linux内核设计与实现,作者:Robert Love
[3],高性能mysql,作者:Baron Scbwartz,Peter Zaitsev,Vadim Tkacbenko
[4],MySQL双写缓冲区(Doublewrite Buffer)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/664984.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【复现】大华 DSS 数字监控系统 任意文件读取漏洞_38

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一: 四.修复建议: 五. 搜索语法: 六.免责声明 一.概述 大华DSS是大华的大型监控管理应用平台,支持几乎所有涉及监控等方面的操作,支持多级跨平台联网等操作。 可…

2024年适合进入股市吗?北京想开股票账户找哪家证券公司交易佣金费用最低?

股市规则是指股票市场中的一系列规则和制度,用于监管和管理股票交易。以下是一些常见的股市规则: 证券法律法规:股市规则的基础是国家的证券法律法规,包括证券法、公司法等,用于规范股票发行、交易和上市等方面的法律规…

重生奇迹MU套装怎么配

汉斯的皮套装:冰之指环,皮护腿,皮盔,皮护手,皮靴,皮铠,流星槌 汉斯的青铜套装:青铜护腿,青铜靴,青铜铠 汉斯的翡翠套装:雷之项链,翡翠护腿,翡翠盔,翡翠铠,远古之盾 汉斯的黄金套装:火之项链,黄金护腿,黄金护手,黄金靴,黄金铠 …

代码随想录算法训练营DAY11 | 栈与队列 (2)

一、LeetCode 20 有效的括号 题目链接:20.有效的括号https://leetcode.cn/problems/valid-parentheses/ 思路:遇到左括号直接进栈;遇到右括号判断站顶是否有匹配的括号,没有就返回flase,有就将栈顶元素出栈&#xff1…

FANUC机器人示教器的菜单变成了图标,如何改成列表的形式?

FANUC机器人示教器的菜单变成了图标,如何改成列表的形式? 如下图所示,开机后按下MENU菜单键时,发现原来的列表形式变成了菜单图标的形式,同时在按F1-F5键时,提示:HMI模式-键不可用, …

向日葵案例解析:无外网接入,医疗设备如何进行远程售后运维

随着医学科学以及生物工程技术的高速发展,医院对于高端医疗设备如MR、CT、B超等高科技成像设备和放射治疗设备的需求激增。医学影像检查作为一种重要的手段,在许多疾病确诊过程中发挥着至关重要的作用。检查结果正确与否,直接影响临床医生对疾…

JS 引导动画

前言 引导动画是程序在某一时刻播放的动画,通常用于向用户介绍程序的功能和特点。 实现效果 实现方式 引导动画的实现方式有很多种,这里我使用的是 CSS 的 clip-path 属性。 技术选型 这里我为什么要选择 clip-path 属性而不是 mask 属性呢&#xf…

阿狸与小兔子的奇幻之旅

在很久很久以前,有一个遥远的国度,这个国度里生活着各种各样的动物,它们和谐共处,幸福快乐。在这个国度里,有一只聪明伶俐的小狐狸,名叫阿狸。 一天,阿狸在森林里散步时,遇到了一只正…

关于网络面试题汇总

什么是TCP/IP五层模型?它们的作用是啥?基于TCP/IP实现的应用(层协议)有哪些? TCP/IP五层模型,从上向下分别是: 应用层:应用程序本身,应用层的作用是负责应用程序之间的…

数据结构篇-05:哈希表解决字母异位词分组

本文对应力扣高频100 ——49、字母异位词分组 哈希表最大的特点就是它可以把搜索元素的时间复杂度降到O(1)。这一题就是要我们找到 “字母异位词” 并把它们放在一起。 “字母异位词”就是同一个单词中字母的不同组合形式。判断“字母异位词”有两个视角:1、所含字…

全面认识DOS系统

目录 一、DOS系统的功能 1.执行命令和程序(处理器管理) 2.内存管理 3.设备管理 4.文件管理 5.作业管理 二、文件与目录 三、文件类型与属性 1.系统属性(S) 2.隐含属性(H) 3.只读属性&#xff08…

初谈类和对象

文章目录 前言类的引入类的定义类的两种定义方式成员命名规则 类的访问限定符及封装访问限定符面试题封装 类的作用域类的实例化类对象模型计算类对象的大小 this指针this指针特性 前言 C语言是面向过程的,关注点是过程;而C面向的是对象,关注…

mysql-FIND_IN_SET查询优化

优化前 SELECTuser_id,user_name,real_name,PASSWORD,real_org_id,real_org_name,real_dept_id,real_dept_name, STATUS FROMsys_user WHEREis_del 0 AND find_in_set( lilong, login_user_account ) 优化后 SELECTuser_id,user_name,real_name,PASSWORD,real_org_id,real…

回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制)

回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制) 目录 回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制&#xff0…

如何处理我们的文本数据成构建词表

我们拿到在拿到一堆语料数据,或者是在网络中爬取下来的文本数据如何处理成为模型能够训练的数据呢?这里有我们先经过停用词和按字分词的处理之后,得到的问答对文本数据,input_by_word.txt 和 target_by_word.txt 。其中&#xff0…

2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测

2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测 目录 2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效…

Docker进阶篇-Docker网络

一、描述 1、docker不启动,默认网络情况 查看网卡情况使用,ifconfig或者ip addr ens33:本机网卡 lo:本机回环网络网卡 virbr0:在CentoS 7的安装过程中如果有选择相关虚拟化的的服务安装系统后,启动网卡时会发现 …

Web实战丨基于Django的简单网页计数器

文章目录 写在前面Django简介主要程序运行结果系列文章写在后面 写在前面 本期内容 基于django的简单网页计数器 所需环境 pythonpycharm或vscodedjango 下载地址 https://download.csdn.net/download/m0_68111267/88795604 Django简介 Django 是一个用 Python 编写的高…

游戏找不到d3dcompiler_43.dll怎么办?多种5种解决方法分享

在运行游戏的过程中,系统遇到了一个关键性的问题,即无法成功找到名为“d3dcompiler_43.dll”的动态链接库文件。这一特定的dll文件对于游戏的正常启动和图形渲染至关重要,它的缺失可能会导致游戏无法运行或者画面无法正确显示。通常情况下&am…

day07-CSS高级

01-定位 作用:灵活的改变盒子在网页中的位置 实现: 1.定位模式:position 2.边偏移:设置盒子的位置 left right top bottom 相对定位 position: relative 特点: 不脱标,占用自己原来位置 显示模…