InnoDB buffer pool(1)[Mysql InnoDB系列]

下面的圖片展現了組成InnoDB存儲引擎的內存結構和磁盤結構。


InnoDB內存結構


Buffer Pool緩衝池

緩衝池是緩衝需要被訪問的表和索引數據的內存區域。爲了加速,緩衝池將頻繁訪問的數據直接放在內存中處理。在專有服務器(dedicated server)上,通常給緩衝池分配高達80%的總內存。

爲了提升大批量讀操作的效率,緩衝池被分成了很個頁(page),每個頁可以容納多個行。爲了提升緩存管理的效率,緩衝池裏的塊是以鏈表的形式存放;基於LRU算法的一種變體,很少使用的數據會隨着時間被踢出緩存。

如何利用緩衝池將頻繁使用的數據留在內存中,是Mysql優化的一個重要方面。

緩衝池LRU算法

緩衝池是按照LRU(least recently used最近最少使用)算法的一種變體來管理的一個鏈表。當進入新的數據頁需要空間時,最近一段時間內最少使用的頁會被踢出,然後新進來的頁會放在列表的中間。中間點的選擇方案是,把列表分成兩個子列表:

  • 列表頭,新頁子列表,最近訪問過的
  • 列表尾,舊頁子列表,最近很少訪問的



    這個算法會將頻繁使用的頁保留在新頁子列表。舊頁子列表包含很少使用的頁;這些頁做好了被踢出的準備。

默認情況下,算法是這樣操作的:

  • 緩衝池的3/8分給舊頁子列表
  • 列表的中間點是新頁子列表的尾部和舊頁子列表的頭部的連接處,即新舊子列表的交界點
  • 當InnoDB將頁讀取進緩衝池,最開始是放在中間點。觸發讀頁進緩衝池的操作除了普通的SQL查詢,還可以是InnoDB自動執行的read ahead操作,即預讀功能。

什麼是read ahead?

一種異步IO請求機制,預先將一組數據頁(一整個區extent,64個頁page)放進緩衝池,因爲這個區有可能很馬上就需要訪問,因此提前做好準備。分爲linear read ahead線性預讀和random read ahead隨機預讀。

  • 線性預讀
    若前一個區內緩存的數據塊數量超過一個固定值(innodb_read_ahead_threshold系統變量),就會根據前一個區的訪問方式來預先讀取一個下一個區中的所有頁
  • 隨機預讀
    一個區內緩存在緩衝池的數據頁數量一旦超過一個固定值(innodb_read_ahead_threshold系統變量),就會將這個區的所有塊都預先緩存
  • 訪問一箇舊頁子列表的頁會讓這個頁變‘新’,它會被移動到緩衝池列表的頭部,並且是新頁列表的頭部。如果頁的讀取是由於被語句需要,則頁立即會被標記爲已訪問並加入新頁子列表,如果是由於read ahead機制被預讀,則不會立即被標記爲已訪問(頁有可能直到被踢出也都不會被訪問)。

  • 緩衝池中的頁會按照最近一次訪問的時間排序,未被訪問的頁會慢慢移向列表的尾部。從中間點寫入頁會導致舊頁列表裏原有的頁往尾部移動。最終會把最久未被使用的哪些頁擠出緩衝池。

默認情況下,查詢讀取的頁會立刻被移動到了新頁子列表,意味着他們會在緩衝池中存留更長時間。全表掃描(例如Mysqldump操作,或者沒有where條件的select語句)會將大量數據加載進行緩衝池,同時會踢出等量更舊的數據,即使新數據或許很難被再次使用。類似地,通過預讀自動被加載進緩衝池之後,一旦被訪問,就會移動到新頁子列表頭部。這些情況都會使得頻繁使用的頁被擠到舊頁子列表,進而被擠出緩衝池。有一種技術是可以優化這種情況的,這項技術通過innodb_old_blocks_time系統變量設置了一個時間閾值(單位爲ms),從第一次訪問一個頁開始,這個時間窗口範圍內的訪問不會將這個頁移動到新也子列表的頭部(暫時放在舊頁子列表,這個時間窗口過後若仍然需要訪問,纔會將這個頁移動到新列表的頭部)。

InnoDB標準監控輸出的BUFFER POOL AND MEMORY部分有一些信息是關於緩衝池LRU算法的操作。

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