InnoDB儲存引擎——Checkpoint技術

readyao發表於2017-03-11

為什麼需要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 DA他的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,重新整理一部分的髒頁到磁碟。

相關文章