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