MySQL是如何保证数据不丢失的?

文章目录

  • 前言
  • Buffer Pool 和 DML 的关系
  • DML操作流程
    • 加载数据页
    • 更新记录
  • 数据持久化方案
    • 合适的时机刷盘
    • 双写机制
    • 日志先行机制
    • 日志刷盘机制
    • Redo Log 恢复数据
  • 总结

前言

上篇文章《InnoDB在SQL查询中的关键功能和优化策略》对InnoDB的查询操作和优化事项进行了说明。但是,MySQL作为一个存储数据的产品,怎么确保数据的持久性和不丢失才是最重要的,感兴趣的可以跟随本文一探究竟。

Buffer Pool 和 DML 的关系

InnoDB中的「Buffer Pool」除了在查询时起到提高效率作用,同样,在insert、update、delete这些DML操作时为了减少和磁盘的频繁交互,也会将这些更新先在Buffer Pool中缓存的数据页进行操作,随后将这些有更新的「脏页」刷到磁盘中。

这个时候就涉及到一个问题:如果MySQL服务宕机了,这些在内存中更新的数据会不会丢失?

答案是一定会存在丢失现象的,只不过MySQL做到了尽量不让数据丢失。接下来来看一下MySQL是怎么做的。

这里还是把结构图贴一下,方便下面介绍时看图理解。

在这里插入图片描述

DML操作流程

加载数据页

通过上文可以知道,行记录是在数据页中,所以,当InnoDB接收到DML操作请求后,还是会去找「数据页」,查找的过程跟上文查询行记录流程是一样。这里说一下,insert的请求会根据主键索引去找数据页,update、delete根据查询条件去找数据页,总之「数据页」要加载到「Buffer Pool」之后才会进行下一步操作。

更新记录

定位到数据页后,insert操作就是往数据页中添加一行记录,delete是标记一下行记录的‘删除标记’,而update则是先删除再添加,这是因为存在可变长的字段类型,比如varchar,每次更新时,这种类型的数据占用内存是不固定的,所以先删除再添加。

这里的删除标记是行记录的字段,也就是除了业务字段数据,InnoDB默认为每行记录添加的字段,所以一个行记录大概如下图,这也是之前提到过的「行格式」。

在这里插入图片描述

找到数据页并且更新记录之后DML操作就算完成了,但是还没有落地到磁盘。

这个时候直接刷新到磁盘视为完成不可以吗?

数据持久化方案

可以是可以,但是如果每次的DML操作都要将一个16KB的数据页刷到磁盘,其效率是极低的,估计也就没有人用MySQL了。但是如果不刷新到磁盘,就会发生MySQL服务宕机数据会丢失现象。MySQL在这里的处理方案是:

  1. 等待合适的时机将批量的「脏页」异步刷新到磁盘。
  2. 先快速将更新的记录以日志的形式刷新到磁盘。

先看第一点,什么时候是合适的时机?

合适的时机刷盘

当「脏页」在「Buffer Pool」中达到某个阈值的时候,InnoDB会将这些脏页刷新到磁盘中。这个阈值可以通过 innodb_max_dirty_pages_pct 这个参数查看或设置,相关命令如下:

-- 查看脏页刷新阈值
show variables like 'innodb_max_dirty_pages_pct'
-- 在线设置脏页刷新阈值,当脏页在Buffer Pool占用70%的时候刷新
SET GLOBAL innodb_max_dirty_pages_pct = 70

在这里插入图片描述

当然,这个合适的时机只是为了减少与磁盘的交互,用来提高性能的,并不能确保数据不丢失。

双写机制

在刷新「脏页」这里还有一个非常重要的注意事项就是:因为InnoDB的页大小为16KB,而一般操作系统的页大小为4KB。意味着InnoDB将这些「脏页」向磁盘刷新时,在操作系统层面会被分成4个4KB的页,这样的话,如果其中有一页因为MySQL宕机或者其他异常导致没有成功刷新到磁盘,就会出现「页损坏现象」,数据也就不完整了。

在这里插入图片描述

所以InnoDB在这里采用的双写机制,在将这些「脏页」刷新到磁盘之前先会往结构图中的「Doublewrite Buffer」中写入,随后再刷新到对应的表空间中,当出现故障时就可以通过双写缓冲区进行恢复。

向「Doublewrite Buffer」就不会发生「页损坏现象」?

Doublewrite Buffer」的大小是独立且固定的,不是基于页的大小来划分的。所以不受操作系统中的页大小限制,也不会发生「页损坏现象」。并且先以顺序IO的方式向「Doublewrite Buffer」写入数据页,再以随机IO异步刷新到表空间这种方式还可以提高写入性能。

在这里插入图片描述

再看第二点,为什么以日志的形式先刷新到磁盘?

日志先行机制

在「Buffer Pool」中更新完数据页后,由于不会及时将这些「脏页」刷新到磁盘,为了避免数据丢失,会将本次的DML操作向「Log Buffer」中写一份并且刷新到磁盘中,相比16KB的数据页来说,这个数据量会小很多,而且写入日志文件时是追加操作,属于顺序IO,效率较高。如下图,哪种方式写入效率更高是显而易见的。

在这里插入图片描述

这里说的日志文件就是经常会听到的「Redo Log」,即使MySQL宕机了,通过磁盘的redolog,也可以在MySQL启动时尽可能的将数据恢复到宕机之前样子。当然,还有「Undo Log」,因为对本文重点没有直接影响,所以不对此展开说明。

这种日志先行(WAL)的机制也是MySQL用于提高效率和保障数据可靠的一种方式。

为什么是尽可能的恢复?

日志刷盘机制

因为「Log Buffer」中的日志数据什么时候向磁盘刷新则是由 innodb_flush_log_at_trx_commitinnodb_flush_log_at_timeout 这两个参数决定的。

  • innodb_flush_log_at_trx_commit默认为1,也就是每次事务提交后就会刷新到磁盘。
  • innodb_flush_log_at_trx_commit设置为0时,则不会根据事务提交来刷新,而是根据innodb_flush_log_at_timeout设置的时间定时刷新,这个时间默认为1秒。
  • innodb_flush_log_at_trx_commit设置为2时,仅将日志写入操作系统中的缓存中,随后跟随根据innodb_flush_log_at_timeout定时刷新。

如果在MySQL服务宕机的时候,「Log Buffer」中的日志没有刷新到磁盘,这部分数据也是会丢失的,在重启后也不会恢复。所以如果不想丢失数据,在性能还可以的情况下,尽量将innodb_flush_log_at_trx_commit设置为1。

「redo log」是怎么恢复数据的?

Redo Log 恢复数据

首先,redo log会记录DML的操作类型、数据的表空间、数据页以及具体操作内容,以 insert into t1(1,'hi')为例,对应的redo log内容大概这样的

在这里插入图片描述

假如 innodb_flush_log_at_trx_commit 的值为1,那么当该DML操作事务提交后,就会将 redo log 刷新到磁盘。成功刷新到磁盘后,就可以视为数据被写入成功。

此时如果「脏页」还没刷新到磁盘便宕机,那么在下次MySQL启动时便去加载redo log,如果redo log存在数据则意味着需要恢复数据。这个时候就可以通过redo log中的内容重新构建「脏页」,从而恢复到宕机之前的状态。

怎么构建「脏页」呢?

其实在每次的redo log写入时都会记录一个「LSN(log sequence number)」,同时这个值在「数据页」中记录最后一次被修改的日志序列位置。MySQL在启动时通过LSN来对比 redo log 和数据页,如果数据页中的LSN小于 redo log 的LSN,则会将该数据页加载到「Buffer Pool」,然后根据 redo log 的内容构建出「脏页」,等待下次刷新到磁盘,数据也就恢复了。如下图

在这里插入图片描述

注意:这个恢复的过程重点在redo上,实际上还涉及到「Change Buffer」、「Undo Log」等操作,这里没有展开说明。

「Doublewrite Buffer」和「redo log」都是恢复数据的,不冲突吗?

不冲突,「Doublewrite Buffer」是对「页损坏现象」的整个数据页进行恢复,Redo Log只能对某次的DML操作进行恢复。

总结

InnoDB通过以上的操作可以尽可能的保证MySQL不丢失数据,最后再总结一下MySQL是如何保障数据不丢失的:

  1. 为了避免频繁与磁盘交互,每次DML操作先在「Buffer Pool」中的缓存页中执行,缓存页有更新之后便成为「脏页」,随后根据innodb_max_dirty_pages_pct这个参数将「脏页」刷新到磁盘。
  2. 因为「脏页」在刷新到磁盘之前可能会存在MySQL宕机等异常行为导致数据丢失,所以MySQL采用日志先行(WAL)机制,将DML操作以日志的形式进行记录到「Redo Log」中,随后根据innodb_flush_log_at_trx_commitinnodb_flush_log_at_timeout这两个参数将「Redo Log」刷新到磁盘,以便恢复。
  3. 在向磁盘刷新「脏页」时,为了避免发生「页损坏」现象,InnoDB采用双写机制,先将这些脏页顺序写入「Doublewrite Buffer」中,随后再将数据页异步刷新到各个表空间中,这种方式既能提高写入效率,又可以保障数据的完整性。
  4. 如果在「脏页」刷新到磁盘之前,MySQL宕机了,那么会在下次启动时通过 redo log 将脏页构建出来,做到数据恢复。
  5. 通过以上步骤,MySQL做到了尽可能的不丢失数据。

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

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

相关文章

【MyBatis学习笔记】MyBatis基础学习

MyBatis基础 MyBatis简介MyBatis特性MyBatis下载和其他持久化层技术对比 核心配置文件详解默认的类型别名 搭建MyBatis开发环境创建maven工程创建MyBatis的核心配置文件创建mapper接口创建MyBatis的映射文件通过junit测试功能加入log4j日志功能 MyBatis获取参数值的两种方式&am…

【无人机学习篇】构建mavros机载电脑连接,从机载电脑获取pixhawk数据

(本文基于的pixhawk版本:6X minibase V2.2 ,固件:apm) 整个的步骤(baseline): 具体的每一步都可以在网上查到教程,这里只是梳理出一个流程。并且ubantu与ros的版本也不是…

Java开发框架和中间件面试题(2)

8.说说自己对Spring MVC的了解? MVC是一种设计模式,Spring MVC是一款很优秀的MVC框架。Spring MVC可以帮助我们进行更简洁的Web层开发,并且它天生与Spring框架集成。SpringMVC下我们一般把后端项目分为Service(处理业务&#xff0…

网上商城怎么做:五大关键步骤

在数字化浪潮中,开设网上商城已经成为商业发展的必然趋势。然而如何搭建一个功能齐全、用户体验优良的网上商城并非易事。以下为您介绍网上商城怎么做的五大关键步骤。 第一步,明确商业模式和定位 在开始搭建网上商城之前,需要清晰地定义你…

基于Java+SpringBoot+Mybaties-plus+Vue+ElementUI+Vant 电影院订票管理系统 的设计与实现

一.项目介绍 基于SpringBootVue 电影院订票管理系统 分为前端和后端。 前端(用户): 登录后支持查看首页、电影、影院和我的信息 支持查看正在热映和即将上映的电影信息 支持购票(需选择影院座位)、看过(评论…

java使用面向对象实现图书管理系统

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN …

基本shell功能实现(exec系列程序替换函数练习)

shell 功能描述思路介绍1.实现常驻进程功能2.实现命令读取功能3. 实现命令解析功能4.实现子进程执行命令功能5.完善功能 补充内容让父进程运行内置命令实现子进程能够获得父进程的环境变量功能(export命令)shell实现重定向功能 全部代码如下:…

『 C++ 』二叉树进阶OJ题

文章目录 根据二叉树创建字符串 🦖🥩 题目描述🥩 解题思路🥩 代码 二叉树的层序遍历(分层遍历) 🦖🥩 题目描述🥩 解题思路🥩 代码 二叉树的层序遍历(分层遍历)Ⅱ 🦖&…

一篇文章带你了解SpringBoot目录结构

前言 SpringBoot是整合Spring技术栈的一站式框架,是简化Spring技术栈的快速开发脚手架,是一个能够快速构建生产级别的Spring应用的工具。SpringBoot是目前流行的微服务框架,倡导“约定优于配置”,简化Spring项目搭建及开发过程。…

速通Python基础语法--运算符篇

一、算术运算符 优先级: 除法的2个问题: 除零异常: 运行时才出现的错误,叫做“抛出异常” 如果程序运行过程中 抛出异常,程序就会直接终止,后面的代码不会执行。 除法的(不)截断问题: %取模/求…

宝塔面板安装MySQL数据库并通过内网穿透工具实现公网远程访问

文章目录 前言1.Mysql 服务安装2.创建数据库3.安装 cpolar3.2 创建 HTTP 隧道 4.远程连接5.固定 TCP 地址5.1 保留一个固定的公网 TCP 端口地址5.2 配置固定公网 TCP 端口地址 前言 宝塔面板的简易操作性,使得运维难度降低,简化了 Linux 命令行进行繁琐的配置,下面简单几步,通…

微信小程序使用--如何生成二维码

一、生成二维码 1.获取token 参照官方文档说明: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html 其中grant_type是写死的,appid和secret是注册小程序的时候获取的,然后会得到一个默认两小…

MyBatis-Plus全套笔记

一、MyBatis-Plus 1.简介 MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 我们的愿景是成为 MyBatis 最好的搭档&…

c jpeg 理论霍夫曼 DC AC表,c程序实现正向逆向转换

此4张表是理论表,不是针对某张图片的特定表。如编码程序不统计生成某图片的专用霍夫曼表,应该也可用理论表代用编码。 1.亮度DC表 左边第一列是二进制位数,就是对此位数编码 中间一列是生成比特流的位数,右边是生成的比特流。 …

本地MinIO存储服务如何创建Buckets并实现公网访问上传文件

文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. 远程调用MinIO服务小结5. 固定连接TCP公网地址6. 固定地址连接测试 前言 MinIO是一款高性能、分布式的对象存储系统,它可以100%的运行在标准硬件上,即X86等…

Seata:打造行业首个分布式事务产品

作者:季敏,阿里云分布式事务产品负责人、Seata 开源项目创始人 微服务架构下数据一致性的挑战 微服务开发的痛点 在 2019 年,我们基于 Dubbo Ecosystem Meetup,收集了 2000 多份关于“在微服务架构,哪些核心问题是开…

SparkSQL的编程模型(DataFrame和DataSet)

1.2 SparkSQL的编程模型(DataFrame和DataSet) 1.2.1 编程模型简介 主要通过两种方式操作SparkSQL,一种就是SQL,另一种为DataFrame和Dataset。 SQL SQL不用多说,就和Hive操作一样,但是需要清楚一点的时候,SQL操作的是…

企业需要哪些数字化管理系统?

企业需要哪些数字化管理系统? ✅企业引进管理系统肯定是为了帮助整合和管理大量的数据,从而优化业务流程,提高工作效率和生产力。 ❌但是,如果各个系统之间不互通、无法互相关联数据的话,反而会增加工作量和时间成本…

【递归 回溯】LeetCode-226. 翻转二叉树

226. 翻转二叉树。 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]示例 2: 输入:root [2,1,3] 输出&#xf…

写给测试同学的福利 | 招募

一、简介 寻找空闲时间有能力进行有偿协助测试的人员,协助大厂产品进行测试优化产品工作 二、要求 1.安卓设备2.具备熟练使用手机的能力 三、你可以得到 1.优先体验相关产品新功能、了解产品走向2.任务有偿:每次任务5-30米 四、需要了解事项 1.嫌…