Mysql 系列 | 日誌模組
了解了 SQL 執行的流程,知道每一條語句都經過連接器、查詢存儲、分析器、優化器、執行器最後到存儲引擎的過程。查詢語句是如此,更新語句也不例外。
不同的是,更新語句會修改表數據,這裡就涉及到兩個重要的日誌模組 redolog 和 binlog。
本篇還是選用 InnoDB 搜索引擎。
系統的日誌模組
之一 redolog
下面引入丁奇的經典比喻。
《孔乙己》這篇文章中,酒店掌柜有一個粉板,專門用來記錄客人的賒賬記錄。
如果賒賬的人不多,他可以把顧客名和賬目寫在板上。
但如果賒賬的人多了,粉板總會有記不下的時候,這個時候掌柜一定還有一個專門記錄賒賬的賬本。
如果有人要賒賬或者還賬的話,掌柜一般有兩種做法:
一是直接把賬本翻出來,把這次賒的賬加上去或者扣除掉;
另一種是先在粉板上記下這次的賬,等打烊以後再把賬本翻出來核算。
在生意紅火櫃檯很忙時,掌柜一定會選擇後者,因為前者操作實在是太麻煩了。
首先,你得找到這個人的賒賬總額那條記錄。你想想,密密麻麻幾十頁,掌柜要找到那個名字,可能還得帶上老
花鏡慢慢找,找到之後再拿出算盤計算,最後再將結果寫回到賬本上。
你想想,如果掌柜沒有粉板的幫助,每次記賬都得翻賬本,效率是不是低得讓人難以忍受?
上面的比喻非常形象地說明了 Mysql 中的 WAL(Write-Ahead-Logging) 技術。
先寫日誌(redolog),再寫磁碟。也就是先寫粉板再寫賬本。
-
redolog 是 InnoDB 引擎特有的日誌。
-
當有數據要更新時,InnoDB 會先記錄 redolog,同時更新記憶體,更新操作就結束了。等到合適的時候(空閑或者粉板寫滿了),再更新磁碟。
-
redolog 有固定大小,就像固定大小的粉板,寫滿就得回到開頭循環寫。
-
write pos 是當前記錄粉板的位置,一邊寫一邊往後移。
-
check point 是擦除的位置,擦除前會把更新記錄到數據文件。
-
redolog 保證了資料庫異常重啟時數據不丟失,這個能力被稱為 crash-safe。
-
(丁奇原圖)
- redolog 默認在 Mysql 的 data 目錄下,ib_logfile0、ib_logfile1、。。。
mysql> show variables like "innodb_log_group_home_dir";
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| innodb_log_group_home_dir | ./ |
+---------------------------+-------+
1 row in set (0.00 sec)
- 設置 redolog 文件大小及個數,默認 2 個文件(innodb_log_files_in_group),每個文件 32M(innodb_log_file_size)
mysql> show variables like "innodb_log_file%";
+---------------------------+----------+
| Variable_name | Value |
+---------------------------+----------+
| innodb_log_file_size | 33554432 |
| innodb_log_files_in_group | 2 |
+---------------------------+----------+
2 rows in set (0.00 sec)
- 設置 redolog 實時直接持久化到磁碟上,保證重啟後數據不丟失。
mysql> show variables like "innodb_flush_log_at_trx_commit";
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1 |
+--------------------------------+-------+
1 row in set (0.00 sec)
之二 binlog
-
binlog 是 Server 層的日誌,叫歸檔日誌。不同於 redolog 只有 InnoDB 有,binlog 任何引擎都可以使用。
-
binlog 是邏輯日誌,記錄語句的原始邏輯;redolog 是物理日誌,記錄數據頁的修改內容。
-
binlog 不會循環寫,一個寫完後切換到寫一個;redolog 有固定的大小。
-
binlog 在 data 目錄下,mysql-bin.xxxxxx。
-
設置 binlog 每次事務直接持久化到磁碟上,保證重啟後數據不丟失。
mysql> show variables like "sync_binlog";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| sync_binlog | 1 |
+---------------+-------+
1 row in set (0.00 sec)
update 的執行過程
update T set c=c+1 where ID=2;
-
執行器調用引擎介面找 ID=2 的數據,如果 ID=2 數據所在的數據頁在記憶體中,則直接返回給執行器。否則先從磁碟讀取再返回。
-
執行器拿到數據,把 c 加 1,得到新的一行數據。然後調用引擎介面,寫入這行數據。
-
引擎將新數據更新到記憶體中,順便記錄 redolog,此時 redolog 處於 prepare 狀態,然後告訴執行器可以提交事務。
-
執行器把 binlog 寫入磁碟,然後調用引擎介面提交事務。redolog 狀態變為 commit。更新完成。
數據恢復
既然記錄了 log,那麼當數據誤操作後,就可以根據資料庫定期備份,加上記錄的 log 方便的恢復到誤操作之前的狀態。
-
先根據備份恢復到臨時表
-
根據 binlog 找到備份後到誤操作前的記錄。
-
把恢復好的臨時庫按需要同步到正式庫中。
只要有 log,就可以恢復到任何時刻的數據狀態。
再也不用擔心誤操作無法恢復了。