Mysql InnoDB Buffer Pool的逻辑链表

Mysql InnoDB Buffer Pool:

innodb_buffer_pool_size:InnoDB Buffer Pool的总大小
innodb_buffer_pool_instances:InnoDB Buffer Pool的个数
innodb_buffer_pool_size/innodb_buffer_pool_instances即为每个instance的大小

每个Buffer Pool Instance有一个page hash链表,通过它,使用space_id和page_no就能快速找到已经被读入内存的数据页,而不用线性遍历LRU List去查找。

Buffer Chunks:

包括两部分:数据页和数据页对应的控制体,控制体中有指针指向数据页。

InnoDB Buffer Pool中page的3种状态:
free page:未被使用的页
clean page:数据未进行修改的页
dirty page:数据被修改过的页

逻辑链表:

链表节点是数据页的控制体(控制体中有指针指向真正的数据页),链表中的所有节点都有同一的属性,引入其的目的是方便管理。

InnoDB Buffer Pool中的3个常用的逻辑链表:

free list:
    存放所有的free page

flush list:
    链表中的所有节点都是dirty page,也就是说这些数据页都被修改过,但是还没来得及被刷新到磁盘上。
    在FLU List上的页面一定在LRU List上,但是反之则不成立。
    一个数据页可能会在不同的时刻被修改多次,在数据页上记录了最老(也就是第一次)的一次修改的lsn,即oldest_modification。不同数据页有不同的oldest_modification,FLU List中的节点按照oldest_modification排序,链表尾是最小的,也就是最早被修改的数据页,当需要从FLU List中淘汰页面时候,从链表尾部开始淘汰。
    加入FLU List,需要使用flush_list_mutex保护,所以能保证FLU List中节点的顺序。

lru list:
    所有新读取进来的数据页都存放在上面。链表按照最近最少使用算法排序,最近最少使用的节点被放在链表末尾,如果Free List里面没有节点了,就会从lru list的队尾淘汰节点。
    LRU List被分为两部分,默认前5/8为young list,存储经常被使用的热点page,后3/8为old list(比例由innodb_old_blocks_pct控制)。
    新读入的page默认被加在old list头,只有满足一定条件后,才被移到young list上,主要是为了防止预读的数据页和全表扫描污染buffer pool。    
    如果一个数据页已经处于young list,当它再次被访问的时候,不会无条件的移动到young list头上,只有当其处于young list长度的1/4(大约值)之后,才会被移动到young list头部,这样做的目的是减少对LRU List的修改,否则每访问一个数据页就要修改链表一次,效率会很低

控制old sublist在lru list中的比重的参数:
innodb_old_blocks_pct:
Dynamic:Yes、Scope:Global、Type:Integer、Default Value:37、Minimum Value:5、Maximum Value:95
    Specifies the approximate percentage of the InnoDB buffer pool used for the old block sublist.
    默认37,一般可以调整到20

控制old sublist移动到new sublist的相关参数:
innodb_old_blocks_time:
Dynamic:Yes、Scope:Global、Type:Integer、Default Value (>= 5.6.6):1000、Default Value (<= 5.6.5):0、Minimum Value:0、Maximum Value:2**32-1
    Specifies how long in milliseconds a block inserted into the old sublist must stay there after its first access before it can be moved to the new sublist. 
    If the value is 0, a block inserted into the old sublist moves immediately to the new sublist the first time it is accessed, no matter how soon after insertion the access occurs. 
    If the value is greater than 0, blocks remain in the old sublist until an access occurs at least that many milliseconds after the first access.
     page在加入到old sublist后,必须等待N毫秒后,才具备move to new sublist的资格


关于Mysql的预读:
随机预读(randomread-ahead)----预读当前extent的所有page
由参数 innodb_random_read_ahead 控制
innodb_random_read_ahead:
Dynamic:Yes、Scope:Global、Type:Boolean、Default Value:OFF、Introduced:5.6.3
    Random read-ahead is a technique that predicts when pages might be needed soon based on pages already in the buffer pool, regardless of the order in which those pages were read. 
    If 13 consecutive pages from the same extent are found in the buffer pool, InnoDB asynchronously issues a request to prefetch the remaining pages of the extent. 
    如果一个extent中有13个连续不断的页被加载到buffer pool中,innodb会异步发起一个请求去读取该extent的剩下所有页

线性预读(linear read-ahead)----预读下一个extent
由参数 innodb_read_ahead_threshold 控制
innodb_read_ahead_threshold:
Dynamic:Yes、Scope:Global、Type:Integer、Default Value:56、Minimum Value:0、Maximum Value:64
    Controls the sensitivity of linear read-ahead that InnoDB uses to prefetch pages into the buffer pool.
    If InnoDB reads at least innodb_read_ahead_threshold pages sequentially from an extent (64 pages), it initiates an asynchronous read for the entire following extent. 
    这种预读只发生在一个边界的数据页(Extend中第一个数据页或者最后一个数据页)上,如果InnoDB顺序读取了一个extent的N页,那么innodb会发起一个异步读去读取the entire following extent。

    参考:http://mysql.taobao.org/monthly/2017/05/01/

你可能感兴趣的:(Mysql)