InnoDb体系架构

组成

image.png
innodb存储引擎有多个内存块,这些内存块组成了一个很大的内存池,主要作用:

  1. 维护进程/线程访问所需要的数据结构、
  2. 缓存磁盘上的数据,同时对磁盘文件的修改在这里做缓存
  3. 重做日志 redo log 的缓冲

后台线程的主要作用:

  1. 负责刷新内存池中的数据,保证缓冲池中的内存是最新的数据。
  2. 将已经修改的数据刷新到磁盘

后台线程

MasterThread

将缓冲池中的数据异步的刷新到磁盘,保证数据的一致性, 包括脏页的刷新、合并插入缓冲 (INSERT BUFFER)、UNDO页的回收等。

IOThread

在InnoDb中大量使用了Async IO来处理IO请求,IO Thread的职责主要是负责这些IO请求的回调(call back)处理。
1.0版本之前共有四个IO Thread,分别是read Thread,write Thread,insert Buffer,log IO Thread。在linux平台下,io参数的大小不能进行调整,但是在window平台下可以调整,1.0版本之前,使用 innodb_file_io_threads进行调整,从1.0.X版本开始,使用 innodb_read_io_threads和 innodb_write_io_threads 设置read 和 write 线程的大小。可以使用命令show engine InnoDb status来查看线程大小。
image.png

Purge Thread

事务被提交后,其所使用的undoLog可能不在需要,因此需要Purge Thread来回收已经使用并分配的undoLog页。
1.1版本之前,purge操作由innnodb引擎的masterThread来完成。
1.1版本之后,purge操作由独立的线程来完成,从而减轻master Thread 的压力,提高cpu的使用率以及存储引擎的性能,
InnoDb1.1版本时,purgeThread只能设置为1个,否则报错。从1.2版本开始,支持设置多个purgeThread,这样能够加快undo页的回收,同时也能进一步利用磁盘的随机读取性能。

Page Cleaner Thread

1.2 版本之后引入了 Page Cleaner Thread,其目的是将之前版本中的脏页的刷新操作放在一个独立的线程去完成。
之前是放在master Thread中。 而其目的是为了 减轻原Master Thread的工作及对于用户查询线程的阻塞,进一步提高 InnoDB存储引擎的性能。

内存

缓冲池

缓冲池简单来说就是一块内存区域,通过内存的速度来弥补磁盘速度 较慢对数据库性能的影响。在数据库中进行读取页的操作,首先将从磁盘 读到的页存放在缓冲池中,这个过程称为将页“FIX”在缓冲池中。下一次再读相同的页时,首先判断该页是否在缓冲池中。若在缓冲池中,称该页 在缓冲池中被命中,直接读取该页。否则,读取磁盘上的页。
对于数据库中页的修改操作,则首先修改缓冲池中页,然后再以一定的速率刷新到磁盘。页从缓冲池刷新到磁盘并不是每次页发生更新时触发,而是通过一种checkPoint的机制刷新回磁盘。
缓冲池的配置通过参数innodb_buffer_pool_size参数来设置。可以通过show variables like ‘innodb_buffer_pool_size’ 来查看缓冲池的大小。
缓冲池中缓存的类型:索引页、数据页、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、innodb存储的锁信息(lock info)、数据字典信息(data dictionary)等。
image.png
从InnoDB 1.0.x版本开始,允许有多个缓冲池实例。每个页根据哈希 值平均分配到不同缓冲池实例中。这样做的好处是减少数据库内部的资源 竞 争 , 增 加 数 据 库 的 并 发 处 理 能 力 。 可以通过参数 innodb_buffer_pool_instances来进行配置,该值默认为1。
查看缓冲池实例的方式有两种
1: 通过命令show engine InnoDb status, 通过类似—BUFFER POOL 0的注释来表 明是哪个缓冲池实例。
image.png
2: 通过information_schema架构下的表来查看
SELECT * FROM information_schema.innodb_buffer_pool_stats;

LRU List、Free List和Flush List

通常来说,数据库中的缓冲池是通过LRU算法来管理的。在innodb存储引擎中,缓冲池中页的大小为16k,innodb对lru算法做了一些优化。
在innodb引擎中,lru列表中加入了midpoint位置,虽然是最新访问的页,但并不是直接放到LRU列表的首部,而是放入到LRU列表的midpoint的位置,这个算法在innodb下称为 midpoint insertion strategy。在默认配置下,该位置在LRU列表长度的 5/8处。midpoint位置可由参数innodb_old_blocks_pct控制 。可以通过命令
show variables like ‘innodb_old_blocks_pct’ 来查看大小,默认是37, 表示新读取的页插入到LRU列表尾端的37%的位置(差不多3/8的位置)。在 InnoDB存储引擎中,把midpoint之后的列表称为old列表,之前的列表称为 new列表。可以简单地理解为new列表中的页都是最为活跃的热点数据。如果觉着自己的热点数据较多,可将 innodb_old_blocks_pct的值设置的小一些。
image.png
midpoint机制设计原因: 若直接将读取到的页放入到LRU的首部,那么某些SQL操作 可能会使缓冲池中的页被刷新出,从而影响缓冲池的效率。常见的这类操 作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至是全 部的页,而这些页通常来说又仅在这次查询操作中需要,并不是活跃的热 点数据。如果页被放入LRU列表的首部,那么非常可能将所需要的热点数据 页从LRU列表中移除,而在下一次需要读取该页时,InnoDB存储引擎需要再 次访问磁盘。
为了解决上边原因中的问题,innodb采用了一个参数为 innodb_old_blocks_time来管理LRU列表,表示页读取到mid位置后多久才会添加到LRU的热端。
image.png
LRU列表用来管理已经读取的页,当数据库刚启动时,LRU是空的,这时页都存在Free列表中,当需要从缓冲池中分页时,首先从Free列表中查找是否有可用的空闲页,若有则将该页从Free 列表中删除,放入到LRU列表中。否则,根据LRU算法,淘汰LRU列表末尾的页,将该内存空间分配给新的页。
当页从old部分加入到new部分时,此时发生的动作称为page made young,而因为innodb_old_blocks_time没有导致页从old部分加入到new部分的操作为page not made young。 可以通过命令 show engine InnoDb status来观察LRU列表及Free列表的使用情况和运行状态。
可以通过information_schema架构下的表innodb_buffer_page_lru来查看LRU数据表
SELECT * FROM information_schema.innodb_buffer_page_lru;
注意 执行命令SHOW ENGINE INNODB STATUS显示的不是当前的状态, 而是过去某个时间范围内InnoDB存储引擎的状态。从上面的例子可以发 现,Per second averages calculated from the last 10 seconds代表的 信息为过去10秒内的数据库状态。
InnoDB存储引擎从1.0.x版本开始支持压缩页的功能,即将原本16KB的 页压缩为1KB、2KB、4KB和8KB。而由于页的大小发生了变化,LRU列表也有 了些许的改变。对于非16KB的页,是通过unzip_LRU列表进行管理的。通过 命令SHOW ENGINE INNODB STATUS可以观察到如下内容:
image.png
对于压缩页的表,每个表的压缩比率可能各不相同。可能存在有的表 页大小为8KB,有的表页大小为2KB的情况。unzip_LRU是怎样从缓冲池中分 配内存的呢? 首先,在unzip_LRU列表中对不同压缩页大小的页进行分别管理。其 次,通过伙伴算法进行内存的分配。例如对需要从缓冲池中申请页为4KB的 大小,其过程如下:
1)检查4KB的unzip_LRU列表,检查是否有可用的空闲页;
2)若有,则直接使用;
3)否则,检查8KB的unzip_LRU列表;
4)若能够得到空闲页,将页分成2个4KB页,存放到4KB的unzip_LRU列 表;
5)若不能得到空闲页,从LRU列表中申请一个16KB的页,将页分为1个 8KB的页、2个4KB的页,分别存放到对应的unzip_LRU列表中。
在LRU列表中的页被修改后,称该页为脏页(dirty page),即缓冲池 中的页和磁盘上的页的数据产生了不一致。这时数据库会通过CHECKPOINT 机制将脏页刷新回磁盘,而Flush列表中的页即为脏页列表。需要注意的 是,脏页既存在于LRU列表中,也存在于Flush列表中。LRU列表用来管理缓 冲池中页的可用性,Flush列表用来管理将页刷新回磁盘,二者互不影响。 同LRU列表一样,Flush列表也可以通过命令SHOW ENGINE INNODB STATUS来查看,Modified db pages项就显示了脏页的数量。
image.png

重做日志缓冲

InnoDB存储引擎首先将重做日志信息 先放入到这个缓冲区,然后按一定频率将其刷新到重做日志文件。重做日 志缓冲一般不需要设置得很大,因为一般情况下每一秒钟会将重做日志缓 冲刷新到日志文件,因此用户只需要保证每秒产生的事务量在这个缓冲大 小之内即可。该值可由配置参数innodb_log_buffer_size控制,默认为 8MB:
image.png
重做日志在三种情况下会将重做日志缓冲中的文件刷新到外部磁盘重做日志缓冲文件中:

  1. masterThread每秒钟将重做日志缓冲刷新到重做日志文件
  2. 事务提交时会刷新文件
  3. redo log buffer空间小于1/2时,会刷新文件

额外的内存池

在InnoDB存储引擎中,对内存的管理是通过一 种称为内存堆(heap)的方式进行的。在对一些数据结构本身的内存进行 分配时,需要从额外的内存池中进行申请,当该区域的内存不够时,会从 缓冲池中进行申请。例如,分配了缓冲池(innodb_buffer_pool),但是 每个缓冲池中的帧缓冲(frame buffer)还有对应的缓冲控制对象 (buffer control block),这些对象记录了一些诸如LRU、锁、等待等信息,而这个对象的内存需要从额外内存池中申请。因此,在申请了很大的 InnoDB缓冲池时,也应考虑相应地增加这个值

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值