Buffer Pool 實例
我們上邊說過,Buffer Pool 本質是 InnoDB 向操作系統申請的一塊連續的內存空間,在多線程環境下,訪問 Buffer Pool 中的各種鏈表都需要加鎖處理,在Buffer Pool特別大而且多線程并發訪問特別高的情況下,單一的 Buffer Pool 可能會影響請求的處理速度。所以在 Buffer Pool 特別大的時候,我們可以把它們拆分成若干個小的 Buffer Pool ,每個 Buffer Pool 都稱為一個實例,它們都是獨立的,獨立地去申請內存空間,獨立的管理各種鏈表,所以在多線程并發訪問時并不會相互影響,從而提高并發處理能力。
我們可以在服務器啟動的時候,通過設置innodb_buffer_pool_instances
的值來修改Buffer Pool實例的個數,那每個Buffer Pool實例實際占多少內存空間呢?其實使用這個公式算出來的:
innodb_buffer_pool_size/innodb_buffer_pool_instances
也就是每個 Buffer Pool 實例占用的大小等于 buffer pool 緩沖池總共的大小除以實例的個數。
innodb_buffer_pool_chunk_size
在MySQL 5.7.5之前,Buffer Pool 的大小只能在服務器啟動時通過配置innodb_buffer_pool_size
啟動參數來調整大小,在服務器運行過程中是不允許調整該值的。不過 MySQL 在5.7.5以及之后的版本中支持了在服務器運行過程中調整 Buffer Pool 大小的功能,但是有一個問題,就是每次當我們要重新調整 Buffer Pool 大小時,都需要重新向操作系統申請一塊連續的內存空間,然后將舊的 Buffer Pool 中的內容復制到這一塊新空間,這是極其耗時的。所以 MySQL 決定不再一次性為某 Buffer Pool 實例向操作系統申請一大片連續的內存空間,而是以一個所謂的 chunk 為單位向操作系統申請空間。也就是說一個 Buffer Pool 實例其實是由若干個 chunk 組成的,一個 chunk 就代表一片連續的內存空間,里邊兒包含了若干緩存頁與其對應的控制塊:
正是因為發明了這個 chunk 的概念,我們在服務器運行期間調整 Buffer Pool 的大小時就是以chunk為單位增加或者刪除內存空間,而不需要重新向操作系統申請一片大的內存,然后進行緩存頁的復制。這個所謂的 chunk 的大小是我們在啟動操作MySQL服務器時通過innodb_buffer_pool_chunk_size啟動參數指定的,它的默認值是134217728,也就是128M。不過需要注意的是,innodb_buffer_pool_chunk_size
的值只能在服務器啟動時指定,在服務器運行過程中是不可以修改的。
show variables like 'innodb_buffer_pool_chunk_size';
Buffer Pool 的緩存頁除了用來緩存磁盤上的頁面以外,還可以存儲鎖信息、自適應哈希索引等信息。
查看Buffer Pool的狀態信息
MySQL 給我們提供了 SHOW ENGINE INNODB STATUS 語句來查看關于 InnoDB 存儲引擎運行過程中的一些狀態信息,其中就包括 Buffer Pool 的一些信息,我們看一下(為了突出重點,我們只把輸出中關于 Buffer Pool 的部分提取了出來):
show engine innodb status\G
這里邊的每個值都代表什么意思如下,知道即可:
- Total large memory allocated: 代表 Buffer Pool 向操作系統申請的連續內存空間大小,包括全部控制塊、緩存頁、以及碎片的大小。
- Dictionary memory allocated: 為數據字典信息分配的內存空間大小,注意這個內存空間和Buffer Pool沒啥關系,不包括在Total memory allocated中。
- Buffer pool size: 代表該Buffer Pool可以容納多少緩存頁,注意,單位是頁!
- Free buffers: 代表當前Buffer Pool還有多少空閑緩存頁,也就是free鏈表中還有多少個節點。
- Database pages: 代表LRU鏈表中的頁的數量,包含young和old兩個區域的節點數量。
- Old database pages: 代表LRU鏈表old區域的節點數量。
- Modified db pages:代表臟頁數量,也就是flush鏈表中節點的數量。
- Pending reads:正在等待從磁盤上加載到Buffer Pool中的頁面數量。
- Pending writes
- LRU:即將從LRU鏈表中刷新到磁盤中的頁面數量。
- flush list:即將從flush鏈表中刷新到磁盤中的頁面數量。
- single page:即將以單個頁面的形式刷新到磁盤中的頁面數量。
- Pages made young:代表LRU鏈表中曾經從old區域移動到young區域頭部的節點數量
- Page made not young :在將innodb_old_blocks_time設置的值大于0時,首次訪問或者后續訪問某個處在old區域的節點時由于不符合時間間隔的限制而不能將其移動到young區域頭部時,Page made not young的值會加1。
- **youngs/s:**代表每秒從old區域被移動到young區域頭部的節點數量。
- **non-youngs/s:**代表每秒由于不滿足時間限制而不能從old區域移動到young區域頭部的節點數量。
- Pages read、created、written:代表讀取,創建,寫入了多少頁。后邊跟著讀取、創建、寫入的速率。
- **Buffer pool hit rate:**表示在過去某段時間,平均訪問1000次頁面,有多少次該頁面已經被緩存到Buffer Pool了。
- young-making rate:表示在過去某段時間,平均訪問1000次頁面,有多少次訪問使頁面移動到young區域的頭部了。
- not(young-making rate):表示在過去某段時間,平均訪問1000次頁面,有多少次訪問沒有使頁面移動到young區域的頭部。
- LRU len:代表LRU鏈表中節點的數量。
- unzip_LRU:代表unzip_LRU鏈表中節點的數量。
- I/O sum:最近50s讀取磁盤頁的總數。
- I/O cur:現在正在讀取的磁盤頁數量。
- I/O unzip sum:最近50s解壓的頁面數量。
- I/O unzip cur:正在解壓的頁面數量。
InnoDB的內存結構總結
InnoDB的內存結構和磁盤存儲結構圖總結如下:
其中的 Insert/Change Buffer 主要是用于對二級索引的寫入優化,Undo空間則是undo日志一般放在系統表空間,但是通過參數配置后,也可以用獨立表空間存放,所以用虛線表示。