MySQL-臟頁的刷新機制


MySQL內存結構-緩沖區

MySQL的緩沖區中有數據頁,索引頁,插入緩沖等等,這個角度是從頁的功能來分類的。本小節從另一個視角關注這些頁,如果從 是否被修改過(和磁盤不一致) 這個角度來區分這些頁,那么頁可以被分為干凈的頁和臟頁。

  • 干凈頁:內存中的數據和磁盤一致
  • 臟頁:內存中的數據和磁盤不一致

本小節主要關注臟頁刷新到磁盤的機制,首先需要了解緩沖區的內存管理細節。

內存管理機制簡述

緩沖區中包含這三大類列表。分別為:LRUList、FreeList、FlushList。

在數據庫剛啟動時,LRUlist中並沒有數據頁,空閑頁都存放在FreeList中,當需要讀取某個頁時,會從free列表中獲取一個空閑頁,讀入數據后,放入LRU列表中;如果free中沒有空閑頁了,那么根據LRU算法淘汰Lru列表中末位的頁。

  • LRU列表:管理已經被讀取的頁
  • Free列表:管理空閑的頁

當LRU中的頁被修改后,頁就變成了臟頁,這個頁也會被加入Flush列表中。注意:這時這個頁既在LRU列表中,又在Flush列表中。

  • Flush列表:管理臟頁

總結:LRUList和FreeList用來管理頁的可用性;Flush列表用來管理臟頁的刷新

臟頁的刷新機制-checkpoint機制
數據修改和讀取只依賴緩沖區行不行?

如果數據修改和讀取只依賴內存的緩沖區,那么一旦數據庫宕機,內存中的數據都會丟失。所以MySQL使用之前講過的redo log來實現異常重啟的數據恢復,redolog相關介紹可以看篇文章:MySQL-redo log 和 binlog

簡單來說,就是在更新緩沖區之前,先寫入redo log,保證異常重啟之后可以正常恢復緩沖區中的數據。

臟頁為什么一定要刷新?

考慮這種情況

  • 緩沖區可以無限大
  • redo log可以無限大或者無限拆分為多個文件

如果緩沖區無限大,可以裝下所有的磁盤數據,redo log也可以無限大,那么就算異常重啟,依靠redo log也可以恢復所有的更新。但現實中,首先,緩沖區依賴的內存空間不可能無限大,現實中有許多TB級別的數據庫,但是目前還沒有TB級別的內存;並且 redo log如果無限大或者有許多個文件,對運維和管理也是一個考驗;最后,如果系統中有大量的修改操作,一旦宕機,恢復的時間也會非常長。

所以自然而然,我們就一定需要把內存中的臟頁按照某種規則刷新到磁盤中,有了刷新這個操作,緩沖區的大小問題和redo log的大小問題都可以解決。

  1. 緩沖區不需要無限大了,因為可以持久化到磁盤
  2. redo log也不需要無限大了,因為一旦持久化到磁盤,redo log中對應的那部分數據就可以釋放。
如何刷新呢?

上部分討論的是臟頁刷新到磁盤的必要性。那具體應該如何刷新呢?MySQL中,刷新的規則叫checkpoint機制。

在InnoDB存儲引擎中,有兩種checkpoint:

  • sharp checkpoint:在數據庫關閉時,刷新所有的臟頁到磁盤,這里有參數控制,默認是開啟的
  • fuzzy checkpoint:刷新一部分臟頁到磁盤中。

關於Fuzzy checkpoint,InnoDB存儲引擎中可能包括如下幾種:

  • 定時刷新 - master thread做
  • Flush LRUlist checkpoint -page cleaner thread做
  • async/sync checkpoint -page cleaner thread做
  • dirty too much checkpoint -?誰做?

刷新機制用更通俗易懂的角度來分析,上面的四種類型可以對應下面的

  • 無論如何,定時刷新
  • 當LRU中列表中空閑頁不足時,強制LRU刪除一些末尾的頁,如果存在臟頁,那么需要checkpoint刷新
    • 使用innodb_lru_scan_depth來控制最少空閑頁的數量
  • 當重做日志不夠用時,從flush 列表中選擇一些頁,強制checkpoint刷新
    • 重做日志有兩個水位:async水位 75% * innodb的總大小;sync水位:90* innodb大小。
    • 當未刷新的數據大小 小於 低水位,不需要刷新
    • 當未刷新的數據大小 大於 低水位,小於高水位,異步刷新,保證刷新后小於 低水位
    • 當未刷新的數據大小 大於 高水位,同步阻塞刷新,保證刷新后小於 低水位。
  • 關注系統中的整體臟頁比例,如果達到一定比例,強制刷新
    • 使用 innodb_dirty_page_pct來控制這個比例數值,默認時75%
master thread中的定時刷新機制

1)InndoDB1.0.x版本之前的master thread。
每秒,會進行一次 dirty too much checkpoint。
每10秒

  • 判斷過去10秒的IO操作是否小於200次,如果是,刷100個臟頁;
  • 判斷系統當前臟頁比例,如果超過70%,刷新100個;如果小於70%,刷新臟頁的10%

2)InndoDB1.2.x版本之前的master thread。
在1.0.x存在硬編碼,每秒最多只會刷新100個臟頁到磁盤中,這種規定其實限制了性能更高的SSD磁盤。

在1.0.x版本,可以使用innodb_io_capacity來表示磁盤io的吞吐量。刷新臟頁的數量由innodb_io_capacity來控制,默認是200。

總結

了解臟頁刷新機制以及相應的參數是很有必要的,當數據庫系統某些性能問題時,要考慮是否是臟頁刷新相關的配置參數不合理導致的。

根據實際業務,考慮緩沖區的大小,redo log的大小,最少空閑頁,臟頁比例,io吞吐量相關參數是否配置合理,根據優化相關參數,解決系統問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM