InnoDB存儲引擎——Checkpoint技術

爲什麼需要Checkpoint技術

InnoDB存儲引擎中的緩存池的目的是協調CPU速度和磁盤速度的差別。數據庫對數據頁的操作首先都是在緩衝池中完成的。如果一條DML語句,如update和delete改變了頁中的記錄,那麼該頁變爲了髒頁,也就是說緩衝池中的頁的內容比磁盤中的頁要新。數據庫需要將新版本的頁從緩衝池刷新到磁盤。

但是如果一個頁每次發生了變化之後,就將新頁的版本刷新到磁盤,那麼這個開銷是非常大的。如果在從緩衝池中將頁的新版本刷新到磁盤時發生了宕機,那麼數據就不能恢復了。爲了避免發生數據丟失的問題,當前事務數據庫系統普遍採用了Write Ahead Log策略,即當事務提交時,先寫重做日誌,再修改頁。當由於發生宕機而導致數據丟失時,通過重做日誌來完成數據的恢復。這也是事務ACID中的D(持久性)的要求。

如果重做日誌可以無限地增大,同時緩衝池也足夠大,能夠緩衝所有數據庫的數據,那麼是不需要將緩衝池中頁的新版本刷新回磁盤的。因爲當發生宕機時,完全可以通過重做日誌來恢復整個數據庫系統中的數據。但是需要滿足兩個條件:重做日誌可以無限地增大,同時緩衝池也足夠大,也就是說內存足夠大,磁盤足夠大存放重做日誌。
不過如果數據庫的內容特別大的話,如果通過重做日誌來恢復的話可能需要很長時間。

Checkpoint技術

Checkpoint技術的目的是解決以下幾個問題:
1)縮短數據庫的恢復時間;
2)緩衝池不夠用時,將髒頁刷新到磁盤;
3)重做日誌不可用時,刷新髒頁;
當數據庫發生宕機時,數據庫不需要重做所有的日誌,因爲Checkpoint之前的頁都已經刷新回磁盤了。所以,數據庫只需要對Checkpoint後的重做日誌進行恢復。這樣就縮短了恢復的時間。

當緩衝池不夠用時,根據LRU算法會溢出最近最少使用的頁,若此頁爲髒頁,那麼需要強制執行Checkpoint,將髒頁也就是頁的新版本刷回磁盤。

重做日誌是可以循環使用的,重做日誌可以被重用的部分是指這些重做日誌已經不需要了,也就是說,即使數據庫宕機了,數據庫恢復操作不需要這部分的重做日誌,所以這部分日誌可以被覆蓋重複使用。
如果重做日誌沒有可以被重複使用的並且重做日誌已經滿了,那麼必須強制產生Checkpoint,將緩衝池中的頁至少刷新到當前重做日誌的位置。

對於InnoDB存儲引擎,是通過LSN(Log Sequence Number)來標記版本的。而LSN是8字節的數字,其單位是字節。每個頁有LSN,重做日誌也有LSN,Checkpoint也有LSN。

mysql> show engine innodb status\G

下面是部分輸出:

---
LOG
---
Log sequence number 2448358
Log flushed up to   2448358
Last checkpoint at  2448358
0 pending log writes, 0 pending chkp writes
8 log i/o's done, 0.00 log i/o's/second

Checkpoint所做的事情就是將緩衝池中的髒頁刷回到磁盤。比較關心的問題是每次刷新多少頁到磁盤,每次從哪裏取髒頁,以及什麼時間觸發Checkpoint。

  • 在InnoDB存儲引擎內部,有兩種Checkpoint,分別爲:

1)Sharp Checkpoint
2)Fuzzy Checkpoint

Sharp Checkpoint發生在數據庫關閉時將所有的髒頁都刷新回磁盤,這時默認的工作方式,即參數innodb_fast_shutdown=1;

mysql> show variables like 'innodb_fast_shutdown';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| innodb_fast_shutdown | 1     |
+----------------------+-------+
1 row in set (0.00 sec)

但是,如果數據庫在運行的時候也使用Sharp Checkpoint,那麼數據庫的可用性就會受到很大的影響。所以,在InnoDB存儲引擎內部使用Fuzzy Checkpoint進行頁的刷新,即只刷新一部分髒頁,而不是刷新所有的髒頁到磁盤。

  • 下面是幾種發生Fuzzy Checkpoint的情況:

1)Mater Thread Checkpoint
2)FLUSH_LRU_LIST Checkpoint
3)Async/Sync Flush Checkpoint
4)Dirty Page too much Checkpoint

  • Mater Thread Checkpoint

對於Mater Thread 中發生的Checkpoint,差不多以每秒或每十秒的速度從緩衝池的髒頁列表中刷新一定比例的頁回磁盤。這個過程是異步的,即此時InnoDB存儲引擎可以進行其它的操作,用戶查詢線程不會阻塞。

  • FLUSH_LRU_LIST Checkpoint

FLUSH_LRU_LIST Checkpoint是因爲InnoDB存儲引擎需要保證LRU列表中需要有差不多100個空閒頁可供使用。在InnoDB1.1.X版本之前,需要檢查LRU列表中是否有足夠的可用空間操作發生在用戶查詢線程中,顯然這會阻塞用戶的查詢操作。倘若沒有100個可用空閒頁,那麼InnoDB存儲引擎會將LRU列表尾部的頁移除。如果這些頁中有髒頁,那麼需要進行Checkpoint,而這些頁來自LRU列表,因爲稱爲FLUSH_LRU_LIST Checkpoint。
從MySql5.6版本,也就是InnoDB1.2.x版本開始,這個檢查被放在了一個單獨的Page Cleaner線程中進行,並且用戶可以通過參數innodb_lru_scan_depth控制LRU列表中可用頁的數量,該值默認是1024;

mysql> show variables like 'innodb_lru_scan_depth';

該參數是MySql5.6版本開始新加入的,所以如果版本太低的話是查不到該參數的:

mysql> show variables like 'version';
+---------------+-------------------------+
| Variable_name | Value                   |
+---------------+-------------------------+
| version       | 5.5.49-0ubuntu0.14.04.1 |
+---------------+-------------------------+
1 row in set (0.00 sec)

mysql> show variables like 'innodb_lru_scan_depth';
Empty set (0.00 sec)
  • Async/Sync Flush Checkpoint

Async/Sync Flush Checkpoint指的是重做日誌文件不可用的情況,這時需要強制將一些頁刷新到磁盤,而此時髒頁是從髒頁列表中選取的。若將已經寫入到重做日誌的LSN記爲redo_lsn,將已經刷新回磁盤最新頁的LSN記爲checkpoint_lsn,則可以定義:
checkpoint_age = redo_lsn - checkpoint_lsn
再定義以下變量:
async_water_mark = 75%*total_redo_log_file_size
sync_water_mark = 90% * total_redo_log_file_size
那麼async_water_mark=1.5GB,sync_water_mark=1.8GB。則:
1)當checkpoint_age < async_water_mark時,不需要刷新任何髒頁到磁盤;
2)當async_water_mark < checkpoint_age < sync_water_mark時觸發Async Flush,從Flush列表中刷新足夠的髒頁回磁盤,使得刷新後滿足checkpoint_age < async_water_mark;
3)checkpoint_age > sync_water_mark,這種情況一般很少發生,除非設置的重做日誌文件太小,並且在進行類似LOAD DATA的BLUK INSERT操作。此時觸發Sync Flush操作,從Flush列表中刷新足夠的髒頁回磁盤,使得刷新後滿足checkpoint_age < async_water_mark;

可以看出Async/Sync Flush Checkpoint是爲了保證重做日誌的循環使用的可用性。在InnoDB1.2.x版本之前,Async Flush Checkpoint會阻塞發現問題的用戶查詢線程,而Sync Flush Checkpoint會阻塞所有的用戶查詢線程,並且等待髒頁刷新完成。從InnoDB1.2.x版本開始,也就是MySql5.6版本,這部分的刷新操作同樣放入到了單獨的Page Cleaner Thread中,所以劊阻塞用戶查詢線程。

  • Dirty Page too much Checkpoint

Dirty Page too much Checkpoint的情況是因爲髒頁的數量太多了,導致InnoDB存儲引擎強制進行Checkpoint,其目的是爲了保證緩衝池中有足夠可用的頁。其可由參數innodb_max_dirty_pages_pct控制:

mysql> show variables like 'innodb_max_dirty_pages_pct';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_max_dirty_pages_pct | 75    |
+----------------------------+-------+
1 row in set (0.00 sec)

innodb_max_dirty_pages_pct值爲75,表示當緩衝池中髒頁的數量佔據75%時,強制進行Checkpoint,刷新一部分的髒頁到磁盤。

發佈了163 篇原創文章 · 獲贊 112 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章