天天看點

MySQL · 特性分析 · innodb_buffer_pool_size線上修改

InnoDB Buffer Pool緩存了表資料和二級索引在記憶體中,提高資料庫效率,是以設定innodb_buffer_pool_size到合理數值對執行個體性能影響很大。當size設定偏小,會導緻資料庫大量直接磁盤的通路,而設定過大會導緻執行個體占用記憶體太多,容易發生OOM。在MySQL 5.7之前innodb_buffer_pool_size的修改需要重新開機執行個體,在5.7後支援了動态修改innodb_buffer_pool_size。本文會根據源碼介紹該特性。

innodb_buffer_pool_size預設值是128M,最小5M(當小于該值時會設定成5M),最大為LLONG_MAX。當innodb_buffer_pool_instances設定大于1的時候,buffer pool size最小為1GB。同時buffer pool size需要是innodb_buffer_pool_chunk_size*innodb_buffer_pool_instances的倍數。innodb_buffer_pool_chunk_size預設為128M,最小為1M,執行個體啟動後為隻讀參數。

如果開啟了AHI(adaptive hash index,自适應哈希索引)就關閉AHI,這裡因為AHI是通過buffer pool中的B+樹頁構造而來。

如果新設定的buffer pool size小于原來的size,就需要計算需要删除的chunk數目withdraw_target。

周遊buffer pool instances,鎖住buffer pool,收集free list中的chunk page到withdraw,直到withdraw_target或者周遊完,然後釋放buffer pool鎖。

停止加載buffer pool。

如果free list中沒有收集到足夠的chunk,則重複周遊收集,每次重複間隔時間會指數增加1s、2s、4s、8s…,以等待事務釋放資源。

鎖住buffer pool,開始增減chunk。

如果改變比較大,超過2倍,會重置page hash,改變桶大小。

釋放buffer_pool,page_hash鎖。

改變比較大時候,重新設定buffer pool大小相關的記憶體結構。

開啟AHI。

在支援動态修改innodb_buffer_pool_size之前,該值的修改需要修改配置項然後重新開機執行個體生效。而重新開機執行個體會導緻使用者連接配接強制斷開,導緻一段時間的執行個體不可用,如果有大事務在復原就需要等待很長時間。

動态修改innodb_buffer_pool_size隻有在收集回收塊;查找持有block阻止buffer pool收集回收chunk的事務;resizing buffer pool操作時會阻塞使用者寫入。而這幾部分操作都是記憶體操作,會較快完成。

如果對innodb_buffer_pool_size修改量很大,同時遇到page cleaner工作時間久,就可能導緻一段時間的阻塞。例如下面一個較為極端的例子,innodb_buffer_pool_instances為1,innodb_buffer_pool_size由18GB改為5M,innodb_buffer_pool_chunk_size為1M,page cleaner loop花費近48s,導緻收集回收塊會花費很長時間,可以看到在測試機器上用時近48s。而這期間的寫入操作也會被阻塞。

正常不需要等待時的記憶體操作會很快。

另一個方面,如果目前有事務占用大量buffer pool資料導緻無法收集到足夠的chunk,resize過程也會變久。下面極端測試中當執行xa rollback復原大事務的時候,innodb_buffer_pool_chunk_size由16M改為5M,即等待了較久時間才完成回收chunk的收集。不過這段時間并不會完全阻塞使用者的操作。

從上面可以看到innodb_buffer_pool_size的online修改相比重新開機對使用者執行個體的影響降低了很多,但也最好選擇業務低峰期和沒有大事務操作時候進行,同時要修改MySQL配置檔案,防止重新開機後恢複到原來的值。

繼續閱讀