MySql学习笔记-InnoDB架构概述:内存结构

InnoDB中的内存部分知识点主要分为以下几大块:Buffer Pool缓冲池、额外内存池、Redo Log Buffer(重做日志缓冲)、双写缓冲池以及涉及到内存数据落盘的逻辑和CheckPoint检查点机制。
在这里插入图片描述

Buffer Pool缓冲池

InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。但是由于CPU速度和磁盘速度之间的鸿沟,基于磁盘的数据库系统通常使用缓冲池记录来提高数据库的的整体性能
所以,缓冲池的大小直接影响着数据库的整体性能,可以通过配置参数 innodb_buffer_pool_size来设置。
更多buffer Pool的资料可以看看这个Buffer Pool 漫谈

data page、index page 数据页和索引页

上文中提到InnoDB中磁盘和内存交互的最小单位是页,当InnoDB存储引擎工作时,需要将每页数据分4次从磁盘中加载到内存中,与数据库相关的所有内容都存储在Page结构里。
Page分为几种类型,数据页和索引页就是其中最为重要的两种类型。

insert buffer page 更新(插入)缓冲

主要针对次要索引的数据插入存在的问题而设计。
在InnoDB引擎上进行插入操作时,次要索引在插入时,数据页的存放还是按照主键进行顺序存放,但是对于次要索引叶节点的插入不再是顺序的了,这时就需要离散的访问次要索引页,由于随机读取的存在导致插入操作性能下降。
InnoDB为此设计了Change (insert) Buffer来进行插入优化。对于次要索引的插入或者更新操作,不是每一次都直接插入到索引页中,而是先判断插入的非主键索引是否在缓冲池中,若在,则直接插入;若不在,则先放入到一个Change Buffer中。看似数据库这个非主键的索引已经插到叶节点,而实际没有,这时存放在另外一个位置。然后再以一定的频率和情况进行Change Buffer和非聚簇索引页子节点的合并操作。这时通常能够将多个插入合并到一个操作中,这样就大大提高了对于非聚簇索引的插入性能。

自适应哈希索引

	InnoDB会根据访问的频率和模式,为热点页建立哈希索引,来提高查询效率。

自适应hash索引在实现上就是一个哈希表,InnoDB会根据访问的频率和模式,为热点页建立哈希索引,来提高查询效率。本身的原理并不复杂,首先哈希表不能太大,因为会有成本开销,太小又不能保证命中率,所以在索引创建上会比较讲究。有兴趣的小伙伴可以看看MySQL · 引擎特性 · InnoDB Adaptive hash index介绍

锁信息

InnoDB存储引擎会在行级别上对表数据进行上锁。不过InnoDB也会在数据库内部其他很多地方使用锁,从而允许对多种不同资源提供并发访问。数据库系统使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性。

数据字典信息

InnoDB有自己的表缓存,可以称为表定义缓存或者数据字典(Data Dictionary)。当InnoDB打开一张表,就增加一个对应的对象到数据字典。主要包含数据库中的数据、库对象、表对象等的元信息(如表结构、数据库名或表名、字段的数据类型、视图、索引、表字段信息、存储过程、触发器等内容)

额外内存池(Addtional memory pool)

额外内存池是InnoDB存储引擎用来存放数据字典信息以及一些内部数据结构的内存空间,控制参数为:

innodb_additional_mem_pool_size

这个参数一般很少用,大部分都是使用默认值,通常只有在mysql实例内数据库对象比较多的时候才会调整参数大小,以确保所有数据都能存放在内存中提高访问效率。这个参数大小是否足够还是比较容易知道的,因为当过小的时候,MySQL 会记录 Warning 信息到数据库的 error log 中,这时候你就知道该调整这个参数大小了。

	注:此参数在 MySQL 5.7.4 中移除。

Redo log Buffer重做日志缓冲

在这里插入图片描述

如上图所示,InnoDB在缓冲池中变更数据时,会首先将相关变更写入重做日志缓冲中,然后再按时或者当事务提交时写入磁盘,这符合Force-log-at-commit原则;当重做日志写入磁盘后,缓冲池中的变更数据才会依据checkpoint机制择时写入到磁盘中,这符 合WAL原则。

在checkpoint择时机制中,就有重做日志文件写满的判断,所以,如前文所述,如果重做日志文件太小,经常被写满,就会频繁导致checkpoint将更改的数据写入磁盘,导致性能抖动。
操作系统的文件系统是带有缓存的,当InnoDB向磁盘写入数据时,有可能只是写入到了文件系统的缓存中,没有真正的“落袋为安”。
InnoDB的innodb_flush_log_at_trx_commit属性可以控制每次事务提交时InnoDB的行为。

  • 当属性值为0时,事务提交时,不会对重做日志进行写入操作,而是等待主线程按时写入每秒写入一次;
  • 当属性值为1时,事务提交时,会将重做日志写入文件系统缓存,并且调用文件系统的fsync,将文件系统缓冲中的数据真正写入磁盘存储,确保不会出现数据丢失;
  • 当属性值为2时,事务提交时,也会将日志文件写入文件系统缓存,但是不会调用fsync,而是让文件系统自己去判断何时将缓存写入磁盘。

innodb_flush_log_at_commit是InnoDB性能调优的一个基础参数,涉及InnoDB的写入效率和数据安全。当参数值为0时,写入效率最高,但是数据安全最低;参数值为1时,写入效率最低,但是数据安全最高;参数值为2时,二者都是中等水平。一般建议将该属性值设置为1,以获得较高的数据安全性,而且也只有设置为1,才能保证事务的持久性。

日志的刷盘机制如下图所示:
在这里插入图片描述

内存数据落盘

整体思路分析

在这里插入图片描述

InnoDB内存缓冲池中的数据page要完成持久化的话,是通过两个流程来完成的,一个是脏页落盘;一个是预写redo log日志

当缓冲池中的页的版本比磁盘要新时,数据库需要将新版本的页从缓冲池刷新到磁盘。但是如果每次一个页发送变化,就进行刷新,那么性能开发是非常大的,于是InnoDB采用了Write AheadLog(WAL)策略和Force Log at Commit机制实现事务级别下数据的持久性。

WAL要求数据的变更写入到磁盘前,首先必须将内存中的日志写入到磁盘;Force-log-at-commit要求当一个事务提交时,所有产生的日志都必须刷新到磁盘上,如果日志刷新成功后,缓冲池中的数据刷新到磁盘前数据库发生了宕机,那么重启时,数据库可以从日志中恢复数据。

为了确保每次日志都写入到重做日志文件,在每次将重做日志缓冲写入重做日志后,必须调用一次fsync操作,将缓冲文件从文件系统缓存中真正写入磁盘。可以通过 innodb_flush_log_at_trx_commit 来控制重做日志刷新到磁盘的策略。

脏页落盘

在数据库中进行读取操作,将从磁盘中读到的页放在缓冲池中,下次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。

对于数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称为CheckPoint的机制刷新回磁盘。

重做日志落盘

这里主要说一下Redo Log Buffer什么时候写入到redo log文件。

Redo Log Buffer写入磁盘的时机,由参数 innodb_flush_log_at_trx_commit 控制,默认是1,表示事务提交后立即落盘。

show VARIABLES like 'innodb_flush_log_at_trx_commit';

用户程序写入数据到磁盘文件时,需要调用操作系统的接口,操作系统本身是有缓冲区的,之后依赖操作系统机制不时的将缓存中刷新到磁盘文件中。用户程序可以执行fsync操作将操作系统缓冲区的数据刷入到磁盘文件中。

0:MySQL每秒一次将数据从log buffer写入日志文件并同时fsync刷新到磁盘中。
每次事务提交时,不会立即把 log buffer 里的数据写入到redo log日志文件的。如果MySQL崩溃或者服务器宕机,此时内存里的数据会全部丢失,最多会丢失1秒的事务。

1:每次事务提交时,MySQL将数据将从log buffer写入日志文件并同时fsync刷新到磁盘中。
该模式为系统默认,MySQL崩溃已经提交的事务不会丢失,要完全符合ACID,必须使用默认设置1。

2:每次事务提交时,MySQL将数据从log buffer写入日志文件,MySQL每秒执行一次fsync操作将数据同步到磁盘中。
每次事务提交时,都会将数据刷新到操作系统缓冲区,可以认为已经持久化磁盘,如果MySQL崩溃已经提交的事务不会丢失。但是如果服务器宕机或者意外断电,操作系统缓存内的数据会丢失,所以最多丢失1秒的事务。

只有设置为1是最安全但是性能消耗的方式,可以真正地保证事务的持久性,但是由于MySQL执行刷新操作 fsync() 是阻塞的,直到完成后才会返回,我们知道写磁盘的速度是很慢的,因此MySQL 的性能会明显地下降。

0和2的性能最好的模式,综合安全性和性能的考虑,在业务中经常使用的2这种模式,在MySQL异常重启时不会丢失数据,只有在服务器意外宕机时才会丢失1秒的数据,这种情况几率是很低的,相对于性能来说,这时可以容忍的。

CheckPoint检查点机制(待补充)

DoubleWrite双写

如果说Insert Buffer给InnoDB存储引擎带来了性能上的提升,那么Double Write带给InnoDB存储引擎的是数据页的可靠性。

在这里插入图片描述
如上图所示,Double Write由两部分组成,一部分是内存中的double write buffer,大小为2MB,另一部分是物理磁盘上共享表空间连续的128个页,大小也为2MB

在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是通过memcpy函数将脏页先复制到内存中的double write buffer区域,之后通过double write buffer再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免操作系统缓冲写带来的问题。在完成doublewrite页的写入后,再讲double wirite buffer中的页写入各个表空间文件中。

如果操作系统在将页写入磁盘的过程中发生了崩溃,在恢复过程中,InnoDB存储引擎可以从共享表空间中的double write中找到该页的一个副本,将其复制到表空间文件中,再应用重做日志。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值