【MySQL】mysql buffer pool结构分析

转自:http://blog.csdn.net/wyzxg/article/details/7700394

其他参考:

《高性能MySQL》 - 8.4.5 InnoDB缓冲池

 

《MySQL技术内幕InnoDB存储引擎》(第二版内容有所更新) - 2.3 InnoDB体系结构

##############################################

书中是先对后台线程进行说明,然后对内存部分进行说明,这样更好理解innoDB引擎内存池在使用时的过程。

【后台线程】

InnoDB有多个内存块,可以认为这些内存块组成了一个大的内存池,负责如下工作:

维护所有进程/线程需要访问的多个内部数据结构。
缓存磁盘上的数据,方便快速的读取,并且在对磁盘文件的数据进行修改之前在这里缓存。
重做日志(redo log)缓冲。

【MySQL】mysql buffer pool结构分析

后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据。此外,将已修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常情况下InnoDB能恢复到正常运行状态。

默认情况下,InnoDB存储引擎的后台线程有7个,4个IO thread,1个master thread,1个锁(lock)监控线程,1个错误监控线程。IO thread的数量由配置文件中的innodb_file_io_threads参数控制,默认为4,可以通过show engine innodb status \G查看IO thread,例如:

【MySQL】mysql buffer pool结构分析
mysql> show engine innodb status \G

*************************** 1. row ***************************
  Type: InnoDB
  Name: 
Status: 
=====================================
...
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (read thread)
I/O thread 4 state: waiting for i/o request (read thread)
I/O thread 5 state: waiting for i/o request (read thread)
I/O thread 6 state: waiting for i/o request (write thread)
I/O thread 7 state: waiting for i/o request (write thread)
I/O thread 8 state: waiting for i/o request (write thread)
I/O thread 9 state: waiting for i/o request (write thread)
【MySQL】mysql buffer pool结构分析

可以看到上面IO线程中的四种分别是insert buffer thread、log thread、read thread、write thread。MySQL 5.5可以对IO thread的read thread、write thread的数量进行配置,默认的read thread、write thread分别增大到4个,默认的insert buffer thread、log thread仍为一个线程,上面也是MySQL 5.5版本的配置,同时不再使用innodb_file_io_threads参数,而是分别使用innodb_read_io_thread和innodb_write_io_thread参数,此参数可根据CPU核数、磁盘IO性能进行调整,如果将read thread或write thread配置很大但实际服务器性能不能满足,会导致线程请求积压,反而会降低性能。

【内存】

InnoDB存储引擎内存由以下几个部分组成:缓冲池(buffer pool)、重做日志缓冲池(redo log buffer)以及额外的内存池(additional memory pool),分别由配置文件中的参数innodb_buffer_pool_size和innodb_log_buffer_size的大小决定。

 

 

##############################################

mysql buffer pool里的三种链表和三种page

buffer pool是通过三种list来管理的
1) free list
2) lru list
3) flush list

buffer pool中的最小单位是page,在innodb中定义三种page
1) free page :此page未被使用,此种类型page位于free链表中
2) clean page:此page被使用,对应数据文件中的一个页面,但是页面没有被修改,此种类型page位于lru链表中
3) dirty page:此page被使用,对应数据文件中的一个页面,但是页面被修改过,此种类型page位于lru链表和flush链表中

buffer pool flush list的工作原理
dirty page如何存在flush链表中?
在flush list中存在的page只能是dirty page,flush list中存在的dirty page是按着oldest_modification时间排序的,当页面访问/修改都被封装为一个mini-transaction,mini-transactin提交的时候,则mini-transaction涉及到的页面就进入了flush链表中,oldest_modification的值越大,说明page越晚被修改过,就排在flush链表的头部,oldest_modification的值越小,说明page越早被修改过,就排在flush链表的尾部,这样当flush链表做flush动作时,从flush链表的尾部开始scan,写出一定数量的dirty page到磁盘,推荐checkpoint点,使恢复的时间尽可能的短。除了flush链表本身的flush操作可以把dirty page从flush链表删除外,lru链表的flush操作也会让dirty page从flush链表删除。

buffer pool lru list的工作原理
总的来说每当一个新页面被读取buffer pool之后,MySQL数据库InnoDB存储引擎都会判断当前buffer pool的free page是否足够,若不足,则尝试flush LRU链表。
在MySQL 5.6.2之前,用户线程在读入一个page (buf_read_page)、新建一个page(buf_page_create)、预读page(buf_read_ahead_linear) 等等操作时,都会在操作成功之后,调用buf_flush_free_margin函数,判断当前buffer pool是否有足够的free pages,若free pages不足,则进行LRU list flush,释放出足够的free pages,保证系统的可用性。

通过判断当前buf pool中需要flush多少dirty pages,才能够预留出足够的可被替换的页面(free pages or clean pages in LRU list tail)。

说明:
可用pages由以下两部分组成:
1. buf pool free list中的所有page,都是可以立即使用的。
2. buf pool LRU list尾部(5+2*BUF_READ_AHEAD_AREA)所有的clean pages。
其中:BUF_READ_AHEAD_AREA为64,是一个linear read ahead读取的大小,1 extent

由于buf_flush_free_margin函数是在用户线程中调用执行的,若需要flush LRU list,那么对于用户的响应时间有较大的影响。因此,在MySQL 5.6.2之后,InnoDB专门开辟了一个page cleaner线程,处理dirty page的flush动作(包括LRU list flush与flush list flush),降低page flush对于用户的影响。
在MySQL 5.6.2前后的版本中,LRU list flush的不同之处在于是由用户线程发起,还是有后台page cleaner线程发起。但是,无论是用户线程,还是后台page cleaner线程,再决定需要进行LRU list flush之后,都会调用buf_flush_LRU函数进行真正的flush操作。

不同之处在于,MySQL 5.6.2之前,用户线程调用的buf_flush_free_margin函数,在判断是否真正需要进行LRU list flush时,将LRU list tail部分的clean pages也归为可以被replace的pages,不需要flush。而在page cleaner线程中,每隔1s,无论如何都会进行一次LRU list flush调用,无论LRU list tail中的page是否clean。这也可以理解,用户线程,需要尽量降低flush的概率,提高用户响应;而后台线程,尽量进行flush尝试,释放足够的free pages,保证用户线程不会堵塞。

Buffer Pool LRU/Flush List flush对比
1).LRU list flush,由用户线程触发(MySQL 5.6.2之前);而Flush list flush由MySQL数据库InnoDB存储引擎后台srv_master线程处理。(在MySQL 5.6.2之后,都被迁移到page cleaner线程中)
2).LRU list flush,其目的是为了写出LRU 链表尾部的dirty page,释放足够的free pages,当buf pool满的时候,用户可以立即获得空闲页面,而不需要长时间等待;Flush list flush,其目的是推进Checkpoint LSN,使得InnoDB系统崩溃之后能够快速的恢复。
3).LRU list flush,其写出的dirty page,需要移动到LRU链表的尾部(MySQL 5.6.2之前版本);或者是直接从LRU链表中删除,移动到free list(MySQL 5.6.2之后版本)。Flush list flush,不需要移动page在LRU链表中的位置。
4).LRU list flush,由于可能是用户线程发起,已经持有其他的page latch,因此在LRU list flush中,不允许等待持有新的page latch,导致latch死锁;而Flush list flush由后台线程发起,未持有任何其他page latch,因此可以在flush时等待page latch。
5).LRU list flush,每次flush的dirty pages数量较少,基本固定,只要释放一定的free pages即可;Flush list flush,根据当前系统的更新繁忙程度,动态调整一次flush的dirty pages数量,量很大。

buffer pool free list工作原理
free链表里存放的是空闲页面,初始化的时候申请一定数量的page,在使用的过程中,每次成功load页面到内存后,都会判断free page是否够用,如果不够用的话,就flush lru链表和flush链表来释放free page,这就可以满足其他进程在申请页面,使系统可用。

【MySQL】mysql buffer pool结构分析,布布扣,bubuko.com

【MySQL】mysql buffer pool结构分析

上一篇:plsql programming 01 plsql概述


下一篇:Oracle中Long类型的使用与不可使用