面試題:了解MySQL的Flush-List嗎?順便說一下臟頁的落盤機制!(文末送書)
Hi,大家好!我是白日夢!
今天我要跟你分享的MySQL話題是:「了解Flush-List嗎?順便說一下臟頁的落盤機制!(文末送書)」
本文是MySQL專題的第 8 篇,共110篇。
一、回顧
現在稍微回顧一下:前面幾篇文章介紹了LRU List、Free List。
MySQL啟動後Buffer Pool會初始化。Buffer Pool也會初始化好N多個空白的快取頁,以及它們的描述數據會被組織成LRU鏈表以及FreeList 雙向鏈表。
這時你從磁碟中讀取一個數據頁,會先從Free List中找出一個空閑快取頁的描述資訊,然後將你讀出的數據頁中載入進快取頁中。同時將快取頁的描述資訊從Free List中剔除,此外該描述資訊塊還會被維護進LRU鏈表中。
數據頁被載入進Buffer Pool後你就可以對其進行變更操作了。
二、Flush List
為了加快響應客戶端的速度,MySQL會在Buffer Pool中對數據進行修改,可是一旦你對LRU鏈表中的快取頁做了修改,那該頁中的數據和磁碟中的數據頁資訊就不一致了!大家一般管這種數據頁叫做臟頁。
為了保證數據的最終一致性,MySQL是需要將臟頁刷新回磁碟的!
但是問題是:需要將哪些數據頁刷新回磁碟呢?
這就引出了Flush List~
Flush List 和 Free List很像,都是由Buffer Pool中數據描述資訊組織而成的雙向鏈表。
一旦你對記憶體中的緩衝頁作出了修改,那該緩衝頁對應的描述資訊塊就會添加進 Flush List。這樣當Buffer Pool中的數據頁不夠用時,我們就可以優先將 Flush List中的臟數據頁刷新進磁碟中。
如果你讀了前幾篇文章那你肯定知道了 LRUList、FreeList、FlushList、Buffer Pool、臟頁、臟數據。
下面乘勝追擊!一起看一下臟頁的落盤機制
三、什麼是臟頁?什麼是臟數據?
-
什麼是臟頁?
我在介紹Flush List 的那篇文章有提及,臟頁就是LRU鏈表中被修改了的快取頁。他們和磁碟中的數據頁不一致,臟頁是需要被刷新回磁碟的。
-
什麼是臟數據?
這個問題其實引出了臟讀的概念。舉個例子:事物A中讀取到了事物B中未提交的數據,我們管這些數據叫做臟數據。
四、臟頁刷回磁碟的時機
當Buffer Pool不夠用時,根據LRU機制,MySQL會將Old SubList部分的快取頁移出LRU鏈表。如果被移除出去的快取頁的描述資訊在Flush List中,MySQL就得將其刷新回磁碟。
InnoDB存儲引擎將臟頁刷回磁碟的時機有蠻多的,你可以把它當作拓展知識大概瀏覽一下。
1、當MySQL資料庫關閉時,會將所有的臟數據頁刷新回磁碟。這個功能由參數:innodb_fast_shutdown=0
控制,默認讓InnoDB在關閉前將臟頁刷回磁碟,以及清理掉undo log。
2、有一個後台執行緒Master Thread會按照每秒或者每十秒的速度,非同步的將Buffer Pool中一定比例的頁面刷新回磁碟中。
3、在MySQL5.7中,Buffer Pool的刷新由page cleaner threads完成。
- 我們可以通過
innodb_page_cleaners
參數控制page cleaner threads執行緒的數量,但是當你將這個數值調整的比Buffer Pool的數量還大時,MySQL會自動將innodb_page_cleaners
數量設置為innodb_buffer_pool_instances
的數量。 - Innodb1.1.x之前需要保證LRU列表中有至少100個空閑頁可以使用。低於這個閾值就會觸發臟頁的刷新。
- 從MySQL5.6,也就是innodb1.2.X開始,
innodb_lru_scan_depth
參數為每個緩衝池實例指定page cleaner threads 掃描Buffer Pool來查找要刷新的臟頁的下行距離。默認為1024,該後台執行緒每秒都會執行一次。
4、當臟數據頁太多時,也會觸發將臟數據頁刷新回磁碟。該機制可由參數innodb_nax_dirty_pages_pct
控制,比如將其設置為75,表示,當Buffer Pool中的臟數據頁達到整體快取的75%時,觸發刷新的動作。現實情況是該參數默認值為0。以此來禁用Buffer Pool早期的刷新行為。
5、當redo log不可用時,也會強制臟頁列表中的臟頁刷新回磁碟。這個機制同樣由一個後台執行緒完成。
六、其他關於臟頁刷新的知識點
刷新臨接數據頁:意思是當MySQL將某臟頁刷新回磁碟時,是否也以相同的態度將該臟頁鄰接的臟頁一併刷新回磁碟。
可以通過參數innodb_flush_neighbors
控制該過程。
- 設置為0時表示,禁用刷新鄰接的功能。
- 設置為1時表示,以相同的態度刷新其鄰接的臟頁。
- 設置為2時表示,以相同的程度刷新臟頁。
那如何選擇將其設置為哪種狀態呢?
你可以根據MySQL實例所在機器的存儲類型來決定。如果為HDD存儲建議將其開啟,因為HDD的磁碟刷新速率較低,開啟該參數後可以有效的減少IO操作。相反如果使用SSD存儲,其本身就有高磁碟IO的特性,建議禁用該參數。
七、推薦閱讀
4、能談談year、date、datetime、time、timestamp的區別嗎?
參考:
//dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html
//dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool-flushing.html
//dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_lru_scan_depth
《MySQL技術內幕》
關注送書!《Netty實戰》
文章公號 首發!連載中!關注微信公號回復:「抽獎」 還可參加抽📖活動