Mysql-InnoDB-数据落盘

2024-01-28 22:52

本文主要是介绍Mysql-InnoDB-数据落盘,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概念

1 什么是脏页?
对于数据库中页的修改操作,则首先修改在缓冲区中的页,缓冲区中的页与磁盘中的页数据不一致,所以称缓冲区中的页为脏页。
2 脏页什么时候写入磁盘?
脏页以一定的频率将脏页刷新到磁盘上。页从缓冲区刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为CheckPoint的机制刷新回磁盘。
3 什么是CheckPoint?
Checkpoint要做的事情是将缓冲池中的脏页数据刷到磁盘上。CheckPoint决定了脏页落盘的时机、条件及脏页的选择,不同的CheckPoint做法并不相同。

保证数据的安全性

落盘的流程图:
在这里插入图片描述

脏页产生了肯定是有一个时间要进行落盘,那么怎么保证修改内存到落盘整个过程中不发生任何的问题呢?

InnoDB采用了Write Ahead Log(WAL)策略和Force Log at Commit机制实现事务级别下数据的持久性。
Force Log at Commit机制:当事务提交时,所有事务产生的日志都必须刷到磁盘。如果日志刷新成功后,缓冲池中的数据刷新到磁盘前数据库发生了宕机,那么重启时,数据库可以从日志中恢复数据,这样可以保证数据的安全性.
Write Ahead Log(WAL)策略:要求数据的变更写入到磁盘前,首先必须将内存中的日志写入到磁盘;InnoDB 的 WAL(Write Ahead Log)技术的产物就是 redo log,对于写操作,永远都是日志先行,先写入 redo log 确保一致性之后,再对修改数据进行落盘。

从上面两个机制来看,Redo log 起着关键作用,我们需要保证Redo Log 能够安全落盘
为了确保每次日志都写入到redo日志文件,在每次将redo日志缓冲写入redo日志后,调用一次fsync操作(从系统的缓存真正刷新到磁盘),将缓冲文件从文件系统缓存中真正写入磁盘。
之所以可以这样做是因为,日志只记录更新操作的也和行信息,大小相对较小。同时日志的写入是顺序的,就是继续往后写。再有日志的刷盘和事务是有关联的,事务提交后刷盘策略可以通过innodb_flush_log_at_trx_commit 来控制,日志记录的是事务中执行的一系列操作,不是单条就会触发更新。

innodb_flush_log_at_trx_commit 这个参数相信也不陌生了:

  • 0时:事务提交时,不会立即把 log buffer里的数据写入到redo log日志文件的。而是等待主线程每秒写入一次。
    特点:
    如果MySQL崩溃或者服务器宕机,此时内存里的数据会全部丢失,最多会丢失1秒的事务。
    写入效率最高,但是数据安全最低;

  • 1时:每次事务提交时,会将数据将从log buffer写入redo日志文件与文件系统缓存,并同时
    fsync刷新到磁盘中。
    特点:
    系统默认配置为1,MySQL崩溃已经提交的事务不会丢失,要完全符合ACID必须使用默认设置1。
    写入效率最低,但是数据安全最高;

  • 2时:事务提交时,也会将数据写入redo日志文件与文件系统缓存,但是不会调用fsync,而是让
    操作系统自己去判断何时将缓存写入磁盘。
    特点:
    事务提交都会将数据刷新到操作系统缓冲区,可以认为是已经持久化到磁盘,但没有真正意义
    上持久化到磁盘。
    如果MySQL崩溃已经提交的事务不会丢失。但是如果服务器宕机或者意外断电,操作系统缓存内的数据会丢失,所以最多丢失1秒的事务。

有了上面的准备工作,真正决定数据什么时候落盘的时机是检查点机制,下面我们来看看检查点是怎样工作的,解决了什么问题?
在这里插入图片描述
1 从这个流程来看,首先它可以避免Redo log日志的堆积。因为我们当前检查点执行以后,数据已经落盘了,那么之前的Redo log就没有作用了可以清理掉不可能再使用到的日志。同时如果数据库发了宕机,这个时候也只需要执行上一个检查点到现在的Redo Log就可以恢复数据。
2 可以解决缓冲池不够用问题,缓冲池不够用时,将脏页刷新到磁盘当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是页的新版本刷回磁盘。
3 redo日志不可用时,刷新脏页当redo日志出现不可用时,Checkpoint将缓冲池中的页至少刷新到当前redo日志的位置。这样就算RedoLog不可用也可以保证不丢失更新。

那么具体的检查点又有所不同
1 可以分为两类
sharp checkpoint:在关闭数据库的时候,将buffer pool中的脏页全部刷新到磁盘中。
fuzzy checkpoint:数据库正常运行时,在不同的时机,将部分脏页写入磁盘。仅刷新部分脏页到磁盘,也是为了避免一次刷新全部的脏页造成的性能问题。

Fuzzy Checkpoint:默认方式,只刷新一部分脏页,不是刷新所有脏页;
主要有以下几种情况:

  • Master Thread Checkpoint :在Master Thread中,会以每秒或者每10秒一次的频率,将部分
    脏页从内存中刷新到磁盘,这个过程是异步的。正常的用户线程对数据的操作不会被阻塞。
  • FLUSH_LRU_LIST Checkpoint:缓冲池不够用时,根据LRU算法会淘汰掉最近最少使用的页,如
    果该页是脏页的话,会强制执行CheckPoint,将该脏页刷回磁盘(由Page Cleaner Thread完
    成);
  • Async/Sync Flush Checkpoint:重做日志不可用的情况,需要强制从脏页列表中选取一些脏页
    刷盘(由Page Cleaner Thread完成)。由于磁盘是一种相对较慢的存储设备,内存与磁盘的交互
    是一个相对较慢的过程。innodb_log_file_size定义的是一个相对较大的值,正常情况下,由前面两
    种checkpoint刷新脏页到磁盘,在前面两种checkpoint刷新脏页到磁盘之后,脏页对应的redo log
    空间随即释放,一般不会发生Async/Sync Flush checkpoint。
  • Dirty Page too much:即脏页数量太多,导致强制进行Checkpoint。由参数
    innodb_max_dirty_pages_pt 来控制,默认75(即75%)。当脏页数量占据75%缓冲池时,刷新一部分脏页到磁盘。(由Page Cleaner Thread完成)

在检查点落盘的过程中也可能会发生异常,这个时候就需要Double Write双写来保证不写失效
所谓的写失效就就比如我们一页的数据为16K,但是我们这个页只写了一半数据库就发生了异常,这个时候页就被损坏了。

在这里插入图片描述

这个时候我们不能通过Redo log来恢复,重做日志中记录的是对页的物理操作,而不是页面的全量记录,而如果发生partial page write(部分页写入)问题时,出现问题的是未修改过的数据,此时重做日志(Redo Log)无能为力。因此引入了双写机制:
Double Write分两个部分:
内存中的Doublewrite buffer,大小为2MB
磁盘上的Doublewrite buffer,大小为2MB,连续的128个页,相当于两个extent
Double write脏页刷新流程:
1 首先复制:脏页刷新时不直接写磁盘,而是先将脏页复制到内存的Doublewrite buffer。
2 再顺序写:内存的Doublewrite buffer分两次,每次1MB顺序地写入共享表空间的物理磁盘上,会立即调用fsync函数同步OS缓存到磁盘中,顺序写性能好。
3 最后离散写:内存的Doublewrite buffer最后将页写入各自表空间文件中,离散写较顺序写入差一些。
在这里插入图片描述
如果操作系统在将页写入磁盘的过程中发生了崩溃,其恢复过程如下:
1 首先InnoDB存储引擎从系统表空间中的Double write中找到该页的一个副本
2 然后将其复制到独立表空间
3 再应用重做日志。
相关配置
innodb_doublewrite:Doublewrite Buffer是否启用开关,默认是开启状态,InnoDB将所有数据存储两次,首先到双写缓冲区,然后到实际数据文件。
Innodb_dblwr_pages_written:记录写入到DWB中的页数量。
Innodb_dblwr_writes:记录DWB写操作的次数。

参考资料:极客时间课件资料

这篇关于Mysql-InnoDB-数据落盘的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/655038

相关文章

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

mysql出现ERROR 2003 (HY000): Can‘t connect to MySQL server on ‘localhost‘ (10061)的解决方法

《mysql出现ERROR2003(HY000):Can‘tconnecttoMySQLserveron‘localhost‘(10061)的解决方法》本文主要介绍了mysql出现... 目录前言:第一步:第二步:第三步:总结:前言:当你想通过命令窗口想打开mysql时候发现提http://www.cpp

MySQL大表数据的分区与分库分表的实现

《MySQL大表数据的分区与分库分表的实现》数据库的分区和分库分表是两种常用的技术方案,本文主要介绍了MySQL大表数据的分区与分库分表的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. mysql大表数据的分区1.1 什么是分区?1.2 分区的类型1.3 分区的优点1.4 分

MySQL错误代码2058和2059的解决办法

《MySQL错误代码2058和2059的解决办法》:本文主要介绍MySQL错误代码2058和2059的解决办法,2058和2059的错误码核心都是你用的客户端工具和mysql版本的密码插件不匹配,... 目录1. 前置理解2.报错现象3.解决办法(敲重点!!!)1. php前置理解2058和2059的错误

Mysql删除几亿条数据表中的部分数据的方法实现

《Mysql删除几亿条数据表中的部分数据的方法实现》在MySQL中删除一个大表中的数据时,需要特别注意操作的性能和对系统的影响,本文主要介绍了Mysql删除几亿条数据表中的部分数据的方法实现,具有一定... 目录1、需求2、方案1. 使用 DELETE 语句分批删除2. 使用 INPLACE ALTER T

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE