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->withdraw
如果待删chunk的page為髒頁,則刷髒
重新加載lru中要删除的頁,從lru中摘除,重新從free清單擷取page老的page放入待删連結清單buf_pool->withdraw
釋放buffer pool鎖
如果需收縮的chunk pages沒有收集全,重複2-6
開始resize
鎖住所有instance的buffer_pool,page_hash
收縮pool:以chunk為機關釋放要收縮的記憶體
清空withdraw清單buf_pool->withdraw
增大pool:配置設定新的chunk
重新配置設定buf_pool->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 動态調整盡量在業務低鋒時進行。