InnoDB体系架构(二)内存
上篇文章 InnoDB体系架构(一)后台线程 介绍了MySQL InnoDB存储引擎后台线程:Master Thread、IO Thread、Purge Thread、Page Cleaner Thread 四种。
这篇文章将介绍 InnoDB体系架构中的内存,主要有四小结分别为:缓冲池、缓冲池的管理、重做日志缓冲、额外内存缓冲。
以下图为InnoDB存储引擎的内存结构。
一、缓冲池
InnoDB存储引擎是基于磁盘存储的,按照页的方式进行管理的,理解为基于磁盘的数据库系统。在数据库系统中,由于CPU(快)与磁盘(慢)数据之间的差异,通常使用缓冲池技术来提高数据库的整体性能。
在数据库进行读取时,首先将磁盘读到的页放入缓冲池中,在下次读取相同页时候,如果该页存在于缓冲池,则优先读取。
对于数据库中页的修改操作,首先先操作缓冲池中的页,然后再通过一种名为Checkpoint的机制 按照一定的频率刷新到磁盘中。
查看InnoDB存储引擎缓冲池可以通过:
show variables like ‘innodb_buffer_pool_size‘\G
自InnoDB1.0+开始,缓冲池有多个,为了减少数据库内部的资源竞争,通过设置 innodb_buffer_pool_instance 来设置缓冲池数量。
二、缓冲池管理(LRU List、Free List 和 Flush List)
1. LRU List
上面说到缓冲池是一个内存区域,里面存放了各种类型的页,那么是如何管理的呢?
InnoDB存储引擎的缓冲池是通过LRU算法来进行管理的,即最频繁使用的页在LRU列表的前端,最少使用的页在LRU列表的尾端。
缓冲池中页的大小默认为16KB,与普通的LRU算法稍有不同的是,InnoDB使用LRU算法进行管理时加入了 midpoint(默认将新读取到的页存放到列表长度为5/8出)可以通过innodb_old_blocks_pct控制。为什么这么做呢? 主要是为了防止某些SQL操作,可能会访问大量的页(超过了原本LRU列表的数量)从而原本热点数据被移除,引起性能问题。
至于mid中的数据多久会加入到LRU的热端呢? 可以通过 set global innodb_old_blocks_time=1000 进行设置。
2. Free List
在数据库刚启动的时候,LRU是空的(没有页),这时候页都存放在一个叫Free List中,当需要从缓冲池中分页时,会从Free列表中查找可用的空闲页,若有,将页从Free List中删除,放入LRU List中,否则根据LRU List 淘汰算法,淘汰LRU List的末尾页。
InnoDB1.0+开始支持压缩页功能,将原本16KB的页压缩为1KB、2KB、4KB、8KB。对于非16KB的页,通过unzip_LRU列表进行管理。 其中LRU列表包含了uzip_LRU列表。
如果需要从缓冲池中申请页大小为4KB的页时,有以下步骤:
1) 检查4KB的unzip_LRU 列表是否有空闲页
2) 有,则使用。
3) 否则,检查8KB的unzip_LRU 列表
4) 有则将页分为 2个 4KB的页,存放到4KB的unzip_LRU列表中。
5) 若不能是,则拆16KB的。
3. Flush List
在LRU列表中页被修改后,该页被称为了脏页,因为缓冲池中的页和磁盘页数据不一致,这时候数据库会通过Checkpoint机制将脏页刷新到磁盘。脏页存在于LRU和Flush列表中,LRU列表用来管理缓冲池中页到可用性,FLush列表用来管理将页刷新回磁盘,两者互不影响。
三、重做日志缓冲
InnoDB存储引擎会首先将重做日志缓冲放到重做日志缓冲区,然后按照一定频率刷新到重做日志文件。一般默认8M(满足绝大部分应用)
以下三种情况都会将重做日志缓冲刷新到日志文件中:
1)Master Thread 每秒刷新一次至日志文件中;
2)每个事务提交会将重做日志缓冲刷新到重做日志日志中。
3)当重做日志缓冲剩余空间小于1/2时。
四、额外的内存池
在innoDB存储引擎中,对内存的管理是通过一种称为内存堆(heap)的方式进行。在对一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请,当该区域的内存不够时,需要从缓冲池中申请。
例如L:分配了缓冲池,但是每个缓冲池中的帧缓冲(frame buffer)还有对应的缓冲控制对象(buffer control block),这些记录了一些诸如LRU、锁、等待等信息,而这个对象的内存就需要从额外内存池中申请。因此在申请了很大的缓冲池是也要考虑相应增加这个值。