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/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章