iT邦幫忙

2021 iThome 鐵人賽

DAY 27
0
自我挑戰組

那些Mysql我不知道的事系列 第 27

調節磁碟和CPU的矛盾 - InnoDB的Buffer Pool

快取的重要性

我們知道不論是聚簇索引或是二級索引,資料都是儲存在表格空間,而表格空間其實只是個抽象概念,實際上就是幾個檔案存放在磁碟裡。
我們都知道資料在磁碟上的速度很慢,根本就跟不上很快的CPU,那這樣要怎麼處理呢?
因此當使用者請求資料的時候,會直接將其對應頁的所有資料存放在記憶體中(就算只有一筆資料),且不會急著釋放這些資料,以當下次有請求的時候可以直接利用,這就是InnoDB的Buffer Pool的重要性。

InnoDB的Buffer Pool簡介

mysql server在啟動的時候就會直接先申請一片連續的記憶體當作Buffer Pool(預設為128mb)。
這也是可以調整的,透過系統變數innodb_buffer_pool_size。注意的是低於5mb就會直接當作是5mb

[server]
innodb_buffer_pool_size = 268435456

Buffer Pool是由一堆控制區塊和緩衝頁組成的,每個控制區塊與緩衝頁是一一對應的。
在填充足夠多的控制區塊與緩衝頁之後,剩下的空間可能不足以再填充一個完整的控制區塊與緩衝頁,這些空間又叫做碎片。

InnoDB一樣使用很多個鏈結串列來管理Buffer Pool

Free鏈結串列內每一個節點代表一個空的緩衝頁,當頁面載入到Buffer Pool時就會從Free鏈結串列裡面找尋空的緩衝頁。

為了快速定位某個頁是否被載入到Buffer Pool,會以表格空間號+頁號作為key,緩衝頁控制區塊位址為value來製作雜湊表。

在Buffer Pool中被修改後的頁稱為髒頁,髒頁不是立即更新的,而是會先加到flush鏈結串列,待之後再更新回磁碟中。

LRU(Leasr Recently Used)鏈結串列:
當Buffer Pool已經滿的時候,我們當然就是要移除中些舊的頁面以加入新的頁面,而要移除的就是那些很少在用的頁面囉。
具體的做法就是當存取某個頁的時候,一開始一定會先加到LRU鏈結串列,將其放在頭部。
如之後又存取的時候也會將其對應的節點移到頭部,也就是說在尾部的節點對應的就是一直沒用到的頁面。
因此如果要移除舊的頁面就優先從LRU的尾部移除就可以解決這問題啦!!

再補充LRU依照使用頻率在畫分成兩個區塊:young區塊(使用頻率很高) 跟 old區塊(使用頻率很低)
為了避免同時載入很多使用頻率低的頁面時誤將使用頻率高的頁面從Buffer Pool移除。

可以透過以下變數查看old區塊大小

mysql> show variables like 'innodb_old_blocks_pct';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+
1 row in set (0.02 sec)

這是指old區塊在LRU中佔37%的意思。

多個Buffer Pool

當Pool太大且併發存取量特別高的時候可能單一Pool效能會不好,這時可以考慮多個Pool,

[server]
innodb_buffer_pool_instances = 2

上一篇
神兵利器 - Optimizer trace
下一篇
小蛙借錢給你的交易概念!!
系列文
那些Mysql我不知道的事30

尚未有邦友留言

立即登入留言