MySQL - InnoDB特性 - Buffer Pool漫谈
轉載自??MySQL - InnoDB特性 - Buffer Pool漫談
緩存管理是DBMS的核心系統,用于管理數據頁的訪問、刷臟和驅逐;雖然操作系統本身有page cache,但那不是專門為數據庫設計的,所以大多數數據庫系統都是自己來管理緩存。由于幾乎所有的數據頁訪問都涉及到Buffer Pool,因此buffer pool的并發訪問控制尤為重要,可能會影響到吞吐量和響應時間,本文主要回顧一下MySQL的buffer Pool最近幾個版本的發展(若有遺漏,歡迎評論補充), 感受下最近幾年這一塊的進步
MySQL5.5之前
只能設置一個buffer pool, 通過innodb_buffer_pool_size來控制, 刷臟由master線程承擔,擴展性差。
?
MySQL 5.5
引入參數innodb_buffer_pool_instances,將buffer pool拆分成多個instance,從而減少對buffer pool的訪問控制,這時候的刷臟還是由Master線程來承擔。
?
MySQL 5.6
引入了buffer Pool page Id轉儲和導入特性,也就是說可以隨時把內存中的page no存下來到文件里,在重啟時會自動把這些Page加載到內存中,使內存保持warm狀態. 此外該版本第一次引入了page cleaner,將flush list/lru上的刷臟驅逐工作轉移到單獨線程,減少了master線程的負擔
?
MySQL 5.7
這個版本發布了一個重要特性:online buffer pool resize. 當然是否是online需要打一個問號,因為在resize的過程中需要拿很多全局大鎖,在高負載場景下很容易導致實例Hang住(81615)。?
和之前不同,buffer pool被分成多個instance,每個instance又由多個chunk組成,每個chunk的大小受到參數innodb_buffer_pool_chunk_size控制,默認128MB, buffer pool resize都是以chunk為單位增加或減少的。
另外一個需要注意的點是:你配置的Buffer Pool Size可能比你實際使用的內存要大,尤其對于大Bp而言,這是因為內部做了對齊處理, buffer pool size必須以 innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances來做向上對齊(80350)
我們知道通常數據文件的IO都被設置成O_DIRECT, 但每次修改后依然需要去做fsync,來持久化元數據信息,而對于某些文件系統而言是沒必要做fsync的,因此加入了新選項O_DIRECT_NO_FSYNC,這個需求來自于facebook. 他們也對此做了特殊處理:除非文件size變化,否則不做fsync。(最近在buglist上對這個參數是否安全的討論也很有意思,官方文檔做了新的說明,感興趣的可以看看 [94912:O_DIRECT_NO_FSYNC possible write hole
](https://bugs.mysql.com/bug.php?id=94912))
再一個重要功能是終于引入了multiple page cleaner, 可以多個后臺線程并發刷臟頁,提供了更好的刷臟性能,有效避免用戶線程進入single page flush。當然這還不夠完美,主要有四點:
如果你對上述幾個問題極不滿意,可以嘗試percona server, 他們向來擅長優化Io bound場景的性能,并且上述幾個問題都解決了,尤其是dblwr,他們做了多分區的改進。
?
MySQL 8.0
增加了一個功能,可以在實例宕機時,core文件里不去掉buffer pool, 這大大減少了core文件的大小。要知道,很多時候實例掛是因為文件損壞,不停的core重啟會很快把磁盤占滿,你可以通過設置參數innodb_buffer_pool_in_core_file來控制。
另外8.0最重要的一個改進就是:終于把全局大鎖buffer pool mutex拆分了,各個鏈表由其專用的mutex保護,大大提升了訪問擴展性。實際上這是由percona貢獻給上游的,而percona在5.5版本就實現了這個特性(WL#8423: InnoDB: Remove the buffer pool mutex?以及?bug#75534)。
原來的一個大mutex被拆分成多個為free_list, LRU_list, zip_free, 和zip_hash單獨使用mutex:
- LRU_list_mutex for the LRU_list;- zip_free mutex for the zip_free arrays;- zip_hash mutex for the zip_hash hash and in_zip_hash flag;- free_list_mutex for the free_list and withdraw list.- flush_state_mutex for init_flush, n_flush, no_flush arrays.由于log system采用lock-free的方式重新實現,flush_order_mutex也被移除了,帶來的后果是flush list上部分page可能不是有序的,進而導致checkpoint lsn和以前不同,不再是某個log record的邊界,而是可能在某個日志的中間,給崩潰恢復帶來了一定的復雜度(需要回溯日志)
log_free_check也發生了變化,當超出同步點時,用戶線程不再自己去做preflush,而是通知后臺線程去做,自己在那等待(log_request_checkpoint), log_checkpointer線程會去考慮log_consider_sync_flush,這時候如果你打開了參數innodb_flush_sync的話, 那么flush操作將由page cleaner線程來完成,此時page cleaner會忽略io capacity的限制,進入激烈刷臟
8.0還增加了一個新的參數叫innodb_fsync_threshold,,例如創建文件時,會設置文件size,如果服務器有多個運行的實例,可能會對其他正常運行的實例產生明顯的沖擊。為了解決這個問題,從8.0.13開始,引入了這個閾值,代碼里在函數os_file_set_size注入,這個函數通常在創建或truncate文件之類的操作時調用,表示每寫到這么多個字節時,要fsync一次,避免對系統產生沖擊。這個補丁由facebook貢獻給上游。
?
其他
當然也有些輔助結構來快速查詢buffer pool:
- adaptive hash index: 直接把葉子節點上的記錄索引了,在滿足某些條件時,可以直接定位到葉子節點上,無需從根節點開始掃描,減少讀的page個數
- page hash: 每個buffer pool instance上都通過輔助的page hash來快速訪問其中存儲的page,讀加s鎖,寫入新page加x鎖。page hash采用分區的結構,默認為16,有一個參數innodb_page_hash_locks,但很遺憾,目前代碼里是debug only的,如果你想配置這個參數,需要稍微修改下代碼,把參數定義從debug宏下移出來
- change buffer: 當二級索引頁不在時,可以把操作緩存到ibdata里的一個btree(ibuf)中,下次需要讀入這個page時,再做merge;另外后臺master線程會也會嘗試merge ibuf。
最后,聽說官方正在努力解決double write buffer的瓶頸問題,期待一下.
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的MySQL - InnoDB特性 - Buffer Pool漫谈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑系统坏了怎么办电脑系统坏了怎么办重装
- 下一篇: 史上最全MySQL 大表优化方案(长文)