首页 > 数据库 >MySQL学习笔记(二)InnoDB内存模型与磁盘同步机制

MySQL学习笔记(二)InnoDB内存模型与磁盘同步机制

时间:2024-09-11 23:54:03浏览次数:11  
标签:同步 RedoLog InnoDB 内存 MySQL 磁盘 数据 page

InnoDB存储引擎

ACID 是我们在数据库设计的时候,尽可能的去满足的设计原则。 A 原子性、C 一致性 I 隔离性 D 持久性,其中 InnoDB 存储引擎就是满足了我们 ACID设计原则的。

内存缓存结构(BufferPool

如果每次获取数据都去磁盘获取,这样效率明显比较慢。所以innoDB为了性能,采用了内存缓存的机制,在内存中缓存一定的数据。我们称之为BufferPool。

BufferPool默认大小为128M。

设置大小,单位:字节

SET GLOBAL innodb_buffer_pool_size=402653184

内存与磁盘数据交互机制

页加载机制

我们知道磁盘里面存的数据首先是表空间,表空间里面的单元是 page 页,页里面的数据是行。 innoDB 在内存跟磁盘交互的方式中选择了 page 页,所以, page 页是内存跟磁盘交互的最小单位。为什么要用page ,有几个点考虑。 1. 如果用行交互,那么假如我查询 200 条数据,那么 200 条数据都不在我们内存的话,需要跟磁盘交互200 次,但是 page 可能只有 1.2 个 page 页。 2. 也不会用 extent 区来交互,因为一个 extent 包含 64 个页。可能我只需要查一条数据,但是会加载64 个页到内存,导致内存浪费。   所以,基于内存的利用率与性能考虑, InnoDB 选择了 page 页。

取数据的流程

查询语句

select * from table where id>2

如果最终返回的数据有id=3、4、5 总共三条数据

1.去bufferpool 中查看3、4、5所在的page是否存在

2.存在就直接返回

3.不存在,根据3、4、5的数据所在的page页,去磁盘加载,加载完后保存到内存

4.下一次查询id=4的数据内存中已经存在,直接返回

预读机制

预读是一种我就算没读也能够提前加载数据到内存的机制。其中用线性预读随机预读两种机制:

1 线性预读
按照访问顺序的页来执行预加载某个区里面的页面有多少个页按顺序访问了,那么就会预加载这个区里面所有的页。
2.随机预读
根据缓存池中已有的页来预加载,如果在缓冲池中找到了来自同一个区连续的13 个页面, InnoDB 会异步发出一个请求来预取该区剩余的页面。

数据同步机制

当我们将数据存放到内存,这时候我们的系统中将存在两分数据,一份在内存,一份在磁盘,这时候如果我们对数据进行操作,可能会导致两边数据不同步,那我们就需要对两边数据进行同步处理。

脏页

对于InnoDB,每次更改数据,会先判断内存是否存在,如果存在,会直接修改内存中的数据,且是以page维度去修改。那么这个page与磁盘中的数据不一致了,我们称其为脏页。

对于没用修改的的页称为干净页,如果分配的page没有数据,则称为空页

Flush链表

对于脏页,我们肯定是要去同步到磁盘的,而这个动作我们称为刷脏,我们应该去哪里寻找脏页呢?

在InnoDB的bufferpool中,会将脏页信息单独放在一个链表中,刷脏的时候只需要从这个链表中寻找即可,而这个链表被称为Flush链表。

异步刷脏

出于对性能的考虑,刷脏的方式是异步执行的。具体的线程数由配置innodb_page_cleaners控制

SELECT @@innodb_page_cleaners; --默认是4 但是不能超过buffer-pool的实例数
SELECT @@innodb_buffer_pool_instances;

刷脏的模式分为3种:

自适应刷脏 自适应:根据重做日志的比例以及脏页的产生速度。 RedoLog 自适应 根据 RedoLog 页的产生速度来自适应,后面会细讲 空闲时间刷新 

双写(doubleWrite

        page页会异步刷新到磁盘,但是如果在写得过程中发生意外退出导致写入失败怎么办?这种情况肯定是不被允许的,所以MySQL提供了一个doubleWrite(双写)机制。

1.当脏页写入到bufferpool中时,同时会被copy到Doublewrite缓冲区中。

2.Doublewrite缓冲区中的数据会先到另一处磁盘文件中,这是一个顺序IO,写入效率非常高。

3.将数据写入到真正的磁盘中。

4.如果写入过程发生意外,可以从另一处磁盘中读取恢复到一致的状态。

Doublewrite为了保证数据的安全性和可靠性,会产生一定的性能损失,这是一种权衡下的结果。

RedoLog

        由于刷脏的过程是异步的,如果在同步到磁盘之前就宕机了,数据就丢失了,那么InnoDB怎么去保证数据的一致性与持久性呢?

        这里我们就要讲下InnoDB 里面的一个很重要的概念叫做 RedoLog(重做日志)         RedoLog又称作重做日志,当我发生异常情况,导致数据丢失的时候,我可以从我的RedoLog 日志中找到我想要的数据。

RedoLog格式

type: 操作类型插入、修改还是删除 spaceId: 表空间 ID page num :锁在的页 data: 修改的前后数据

RedoLog file存储

        InnoDB通过 RedoLog 解决数据丢失的问题。所以 RedoLog 肯定是一个基于磁盘的数据结构,肯定会写入磁盘,每次sql 语句提交的时候,都会去写入RedoLog。 RedoLog是一种顺序IO,纪录了哪个页,哪个磁盘哪个扇区,哪个offset的变更,是循环写入的。

RedoLog写入方式

        RedoLog的目的,是去保证我的数据页在内存,但是还没有同步到磁盘的时候,宕机导致的数据丢失。         所以在sql语句提交之前,肯定会保存改动的 Redolog 到 redolog file 文件。当改动数据还在内存,没有同步到磁盘就宕机的时候,会通过RedoLog 文件里面找到改动点,进行同步到磁盘。         但是RedoLogFile 的大小是固定的,写入的日志数量是有限制的,并且它的目的只是去保证数据不丢失,数据落盘了,这些日志就没有用了,所以 RedoLog采用的是循环覆盖写的方式。 为什么不直接实时数据同步到磁盘? 答:出于对性能的考虑 1. 因为 bufferPool 跟磁盘交互的最小单位是 page ,所以,只要 page 里面改动一条数据,整个page 都会进行跟磁盘同步,导致不必要的同步。 而RedoLog只会同步某些记录。 2. 你改动的数据是随机的,不是顺序的,随机 IO 的性能比较慢,但是 RedoLog是一直往上加,是顺序 IO ,速度比数据 page 同步要快。

RedoLog Buffer

redolog是为了保证数据一致性跟持久性的同时,性能得到保证,出于性能考虑,又在内存中申请了一个LogBuffer区间,这个内存区间用来缓存我们的RedoLog, RedoLog不马上写到磁盘,而是先写到 LogBuffer,然后再从Log Buffer同步到磁盘。

这个buff同步时机:

1.buffer空间不足时

buffer是有大小限制的,可以通过innodb_log_buffer_size来进行设置,当内存不足时,会将buffer数据刷新到磁盘

2.事务提交时

为了保证持久性,每次事务提交时,都会根据配置的策略都会把logBuffer的数据刷新到磁盘

3.后台异步线程刷新

后台有一个线程,大约每秒都会刷新一次log buffer中的redo日志到磁盘

4.正常关闭服务器时

....

Redolog Buffer跟磁盘的同步

        我们知道了,LogBuffer什么时候刷新到磁盘了,那么只要触发刷新到磁盘,就能百分比保证数据不丢失么?如果不丢失,那么性能是不是又很 慢。

        所以作者提供不同的同步方案,能够让用户在性能与数据安全性2 个方面自己做取舍。
SELECT @@innodb_flush_log_at_trx_commit; 默认设置为1
1 :每次事务提交时,将日志刷新到磁盘,安全性高,能够保证持久性,默认配置 0 :每秒从内存写到操作系统,并且刷新( fsync() )到硬盘,可能会导致数据丢失 2 :每次写入 logbuffer 并且写到操作系统,但是每秒 fsync() 到磁盘,最终刷新交给操作系统操作,只要操作系统不挂,也能保证持久性,但是操作系统挂了,数据没刷新就会数据丢失

标签:同步,RedoLog,InnoDB,内存,MySQL,磁盘,数据,page
From: https://blog.csdn.net/qq_36509457/article/details/142151995

相关文章

  • 【重学 MySQL】二十五、等值连接vs非等值连接、自连接vs非自连接
    【重学MySQL】二十五、等值连接vs非等值连接、自连接vs非自连接等值连接(Equijoin)vs非等值连接(Non-equijoin)等值连接(Equijoin)非等值连接(Non-equijoin)自连接(Self-join)vs非自连接(Non-self-join)自连接(Self-join)非自连接(Non-self-join)总结在MySQL中,连接(J......
  • 【重学 MySQL】二十四、笛卡尔积的错误和正确的多表查询
    【重学MySQL】二十四、笛卡尔积的错误和正确的多表查询笛卡尔积的理解和错误笛卡尔积的理解定义例子在数据库中的应用总结笛卡尔积的错误正确的多表查询使用INNERJOIN使用WHERE子句(隐式内连接)总结在数据库查询中,特别是涉及到多表查询时,理解笛卡尔......
  • 整数和浮点数在内存中储存
    1.整数的储存在生活中,我们通常运用十进制计数。而在计算机数据在内存中是以二进制的方式存储。1).整数的存储方式整数的2进制表示方法有三种,即原码、反码和补码 有符号的整数,三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,最高位的⼀位是被......
  • MySQL原理之UUID主键分析,插入或更新语法分析
    目录1MySQL不能用UUID做主键1.1前言1.2mysql和程序实例1.2.1准备工作1.2.2开始测试1.2.3程序写入结果1.2.4效率测试结果1.3使用uuid和自增id的索引结构对比1.3.1自增id1.3.2uuid1.4自增id缺点1.5雪花算法2插入或更新2.1onduplicatekey2.1.1定义2.1.2values函数2......
  • 内存延迟对Zen5游戏性能影响有多大!为何首发评测我们会用技嘉X670E AORUS XTREME主板
    一、前言:为什么我们会一直使用技嘉X670E主板做锐龙处理器首发评测很多同学一直好奇,为什么我们在各种锐龙平台的评测中都会优先使用技嘉X670主板?也有同学很疑惑,为什么海外媒体的游戏性能测试,锐龙79700X连i7-14700K都打不过,而在我们这里却与i9-14900K旗鼓相当?主要原因是Zen5架构......
  • 内存屏障简介
    内存屏障编译乱序异步场景中,经常使用多线程一起处理任务并且通过一个共享变量进行状态的共享,如下,function2在请求data数据时通过status判断数据是否就绪,function1准备数据完成后修改status。boolstatus=false;chardata[50]="Hello";voidfunction1(){strcp......
  • DBeaver 连接 mysql 报错:Public Key Retrieval is not allowed
    前言DBeaver连接mysql报错:PublicKeyRetrievalisnotallowed遇到"PublicKeyRetrievalisnotallowed"错误时,通常意味着你正在使用的身份验证方法需要加密连接,但是没有正确地配置客户端或服务器来支持这种加密。解决第一种可以在连接字符串中添加allowPublicKeyRe......
  • mysql 连接失败:message from server: "Host '192.168.xx.xxx' is not allowed to conn
    前言mysql连接失败:messagefromserver:"Host'192.168.xx.xxx'isnotallowedtoconnecttothisMySQLserver"解决错误信息表明你尝试从IP地址192.168.xx.xxx连接到MySQL服务器,但是该IP地址没有被授权连接权限。为了解决这个问题,你需要确保你的MySQL用户权限......
  • Linux 安装MySQL
    前言:根据对应的系统位数,选择需要下载的文件。查看系统位数getconfLONG_BIT一、下载MySQL1.手动去官网下载官网地址:MySQL::DownloadMySQLCommunityServer(ArchivedVersions)2.Linux命令下载通过Linux命令下载:wgethttps://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-对......
  • BUG: pymysql executemany不支持insert on duplicate key update
    pymysql的executemany()方法支持传入单个SQL和一个sequenceofrecords(sequenceormapping)来同时写入多条数据。例如:sql="insertintot(c1,c2)values(%s,%s)"args=[(1,2),(3,4)]cursor.executemany(sql,args)#Ifargsisalistortuple,%scanbeusedas......