Mysql InnoDB Buffer Pool

參考書籍《mysql是怎樣運行的》系列文章目錄和關于我
一丶為什么需要Buffer Pool對于InnoDB存儲引擎的表來說,無論是用于存儲用戶數據的索引,還是各種系統數據,都是以頁的形式存放再表空間中,歸根結底還是存儲再磁盤上 。因此InnoDB存儲引擎處理客戶端的請求是,如果需要訪問某個頁的數據,需要把完整的頁數據加載到內存中,即便是只需要一條數據,也需要把整個頁的數據加載到內存后進行讀寫訪問 。如果沒用緩存那么一條sql需要進行多次的磁盤IO操作,如果在讀寫頁后將其緩存在內存中,便可以減少這種磁盤IO提高mysql性能 。
二丶InnoDB Buffer Pool及其內部組成InnoDB 會在mysql服務器起到是就向操作系統申請一塊連續的內存,(innodb_buffer_pool_size可以控制大小,單位字節)用來對InnoDB的頁做緩存操作 。
Buffer Pool對應一片連續的內存被劃分為若干個頁面,頁面的大小和InnoDB頁面大小一致(16kb)每一個buffer pool 頁都對應一些控制信息(表空間編號,頁號等)這些控制信息被抽象為控制塊(后文我們把buffer pool的頁稱為緩沖頁,和表空間中頁做區分)

Mysql InnoDB Buffer Pool

文章插圖
三丶空閑緩沖頁管理——free 鏈表從磁盤上讀取一個頁到buffer pool中時,應該把這個頁緩存到哪兒昵 。buffer pool的做法時將空閑的緩沖頁對應的控制塊作為一個節點放在鏈表中,這個鏈表稱作free鏈表 。
Mysql InnoDB Buffer Pool

文章插圖
其中有一個基節點負責記錄鏈表的頭和尾,每一個空閑的頁都將在free 鏈表中串聯起來 , 每當innodb需要緩存一個頁的時候,就通過基節點獲取一個空閑的buffer pool 緩沖頁,然后在這個緩沖頁中記錄下表空間,頁號之類的信息 。然后把緩沖頁對應的free鏈表節點移除 。
在緩存一個頁的時候,還需要判斷當前頁是否已經被緩存,innodb 對已經緩存的頁,根據其表空間和頁號兩個值作為hash的key , 建立hash表,這樣可以很快的進行判斷 。
四丶緩沖頁刷盤——flush鏈表當innodb修改一個磁盤上的頁并緩存到buffer pool中 , 這時候內存中緩存的數據和磁盤就不一致這種頁稱為臟頁 。如果每次執行完修改都立馬將數據刷新到磁盤中的頁會影響到程序的性能,所以innodb不會立馬刷新到磁盤 , 而是使用flush鏈表將臟頁對應的控制塊串聯起來
Mysql InnoDB Buffer Pool

文章插圖
五丶緩沖空間不夠怎么辦——LRU鏈表管理1.簡單的LRU鏈表buffer pool的大小畢竟是有限的 , 當free 鏈表中不存在更多空閑的緩沖頁了,這時候就需要采取一些淘汰策略對一些無用的緩沖頁進行淘汰 。
這里就是涉及到兩個問題:什么樣的緩沖頁是無用的,如何維護這些緩沖頁來實現此淘汰策略 。這時候自然是使用LRU算法(最近最少使用)淘汰最近最少使用到緩沖頁 。LRU算法使用一個鏈表來實現,當innodb訪問某個頁的時候:
  • 如果該頁不在buffer pool中 , 那么把該頁從磁盤加載到buffer pool中的緩沖頁是,就把該頁的控制塊放在LRU鏈表的頭部
  • 如果該頁已經在buffer pool中 , 那么移動節點到LRU鏈表頭部
這樣可以實現,被使用到緩沖頁,會盡量靠近LRU鏈表的頭部,自然而然尾部便是最近最少使用到的數據 。LRU算法基于——最近使用到的數據,后續也會到使用到的思想,使用LRU可以提高Buffer pool緩存的命中率 。
2.簡單LRU鏈表無法解決的問題