天天看點

MySQL · 特性分析 · innodb buffer pool相關特性

innodb buffer pool做為innodb最重要的緩存,其緩存命中率的高低會直接影響資料庫的性能。是以在資料庫發生變更,比如重新開機、主備切換執行個體遷移等等,innodb buffer poll 需要一段時間預熱,期間資料庫的性能會受到明顯影響。

另外mysql 5.7以前innodb buffer pool緩存大小修改不是動态的,重新開機才能生效。是以innodb buffer pool的預熱和innodb buffer pool大小的動态修改,對性能要求較高的應用來說是不錯的特性,下面我來看看這兩個特性的具體實作。

buffer pool預熱分為dump過程和load過程,均由背景線程buf_dump_thread完成。

比如使用者發起set指令

set 指令會立刻傳回,具體操作由buf_dump_thread來實作。

dump 過程

鎖buf_pool

周遊lru連結清單,将(space, pageno) 先收集到數組

釋放鎖

再将資料寫入innodb_buffer_pool_filename定有的檔案中

load過程

從檔案讀入數組

按(space,pageno)排序資料

依次同步讀取頁到buffer pool中

dump過程一般比較快,而load過程相對要慢些。

通過<code>innodb_buffer_pool_dump_status</code>、<code>innodb_buffer_pool_load_status</code>可檢視dump/load的狀态

另外5.7引入了performance_schema.events_stages_current來顯示load進度,每load 32m會更新一條進度資訊

work_estimated表示總page數

work_completed表示目前已load page數

dump檔案的資料格式如下

dump檔案比較簡單,我們可以編輯此檔案來預加載指定page,比較靈活。

5.7 開始支援buffer pool 動态調整大小,每個<code>buffer_pool_instance</code>都由同樣個數的chunk組成(chunks數組), 每個chunk記憶體大小為<code>innodb_buffer_pool_chunk_size</code>(實際會偏大5%,用于存放chuck中的block資訊)。buffer pool以<code>innodb_buffer_pool_chunk_size</code>為機關進行動态增大和縮小。調整前後<code>innodb_buffer_pool_size</code>應一直保持是<code>innodb_buffer_pool_chunk_size</code>*<code>innodb_buffer_pool_instances</code>的倍數。

同樣的buffer pool動态調整大小由背景線程<code>buf_resize_thread</code>,set指令會立即傳回。通過<code>innodb_buffer_pool_resize_status</code>可以檢視調整的運作狀态。

resize流程

如果開啟了ahi,需禁用ahi

如果是收縮記憶體

計算需收縮的chunk數, 從chunks開始尾部删除指定個數的chunk.

從free_list中摘除待删chunk的page放入待删連結清單buf_pool-&gt;withdraw

如果待删chunk的page為髒頁,則刷髒

重新加載lru中要删除的頁,從lru中摘除,重新從free清單擷取page老的page放入待删連結清單buf_pool-&gt;withdraw

釋放buffer pool鎖

如果需收縮的chunk pages沒有收集全,重複2-6

開始resize

鎖住所有instance的buffer_pool,page_hash

收縮pool:以chunk為機關釋放要收縮的記憶體

清空withdraw清單buf_pool-&gt;withdraw

增大pool:配置設定新的chunk

重新配置設定buf_pool-&gt;chunks

如果改變/縮小超過2倍,會重置page hash,改變桶大小

釋放buffer_pool,page_hash鎖

如果改變/縮小超過2倍,會重新開機和buffer pool大小相關的記憶體結構,如鎖系統(lock_sys_resize),ahi(btr_search_sys_resize), 資料字段(dict_resize)等

如果禁用了ahi,此時開啟

由上可以看出,擴大記憶體比縮小記憶體相對容易些。縮小記憶體時,如果遇到有事務一直未送出且占用了待收縮的page時,導緻收縮一直重試,error log會列印這種重試資訊,

包含可能引用此問題的事務資訊。為了避免頻繁重試,每次重試的時間間隔會指數增長。

以上步驟中resize階段buffer pool會不可用,此階段會鎖所有buffer pool, 但此階段都是記憶體操作,時間比較短。收縮記憶體階段耗時可能會很長,也有一定影響,但是每次都是以instance為機關進行鎖定的。

總的來說,buffer pool 動态調整大小對應用的影響并不大。

重新加載lru中要删除的頁的影響

search 過程中btr遊标儲存的page可能重新加載過,自适應哈希儲存的root page也可能重新加載過, 都需要重新讀取。

buffer pool 預熱 和buffer pool 動态調整大小,這兩功能相輔相承的。buffer pool 動态調整大小隻适用于執行個體在主機本地更新的情況,如果使用者修改buffer pool大小,同時涉及跨機遷移,那麼buffer pool 預熱功能就排上用場了。

另外buffer pool 動态調整盡量在業務低鋒時進行。