1. 程式人生 > 資料庫 >Mysql 日誌系統

Mysql 日誌系統

bin-log & redo-log & undo log

1. 避免從刪庫到跑路 - bin log

1.1 什麼是bin log

  • binlog 即二進位制日誌,他記錄了引起或可能引起資料庫改變事件,包括事件發生的時間、開始位置、結束位置等資訊,select、show 等查詢語句不會引起資料庫改變,因此不會被記錄在 binlog 中
  • 對於事務的執行,只有事務提交時才會一次性寫入 binlog,對於非事務操作,則每次語句執行成功後都會直接寫入 binlog
  • 因此,基於 binlog,我們可以看到每一次對資料庫的修改是在何時以何種方式執行的,從而可以實現對任意條操作的回滾,當然
  • mysql 的主從同步機制也是依賴 binlog 來實現的,binlog 讓從資料庫可以精準還原主庫的每一個操作

1.2 bin log結構

binlog是可以追加寫入的,追加寫入指的是binlog檔案寫到一定大小後會切換到下一個檔案,並不會覆蓋以前的檔案

1.3 如何靠bin log恢復資料

bin log會記錄所有的邏輯操作,並且採用“追加寫”的形式,如果你的DBA承諾說半個月內可以恢復,那麼備份系統中一定會儲存最近半個月的所有bin-log,同時系統會定期做整庫備份
當需要恢復到指定的某一秒時,比如某天下午兩點發現中午12點有一次誤刪表,需要找回資料,那麼可以這麼做

  • 首先,找到最近的一次去全量備份,如果你運氣好,可能就是昨天晚上的一個備份,從這個備份恢復到臨時庫
  • 然後,從備份的時間點開始,將備份的binlog一次取出來,重放到中午誤刪表之前的那個時刻

這樣你的臨時庫就和誤刪之前的線上庫一樣了,然後你可以把表資料從臨時庫中求出來,按需求恢復到線上庫中

2. 異常情況下的事務安全 - 重做日誌redo log


2.1 更新操作是否應該直接操作磁碟資料?

對於每次更新來說,最簡單的方法就是每次都把操作記錄到磁碟,去磁碟找相應的資料,再進行更新,但這樣頻繁的IO操作會導致效能的下降

2.2 WAL技術


再同一事務中,當有記錄需要更新時,InnoDB引擎將修改結果更新到記憶體後,會在redo log新增一行記錄來記錄“需要在哪個資料頁上做什麼修改”,並將該記錄的狀態置為prepare

,等到commit提交事務後,會將此次事務中在redo log新增的記錄的狀態都置為commit狀態,同時,InnoDB引擎會在適當的時候,將redo log中狀態為commit的記錄的修改更新到磁盤裡面,而這個更新往往是在系統比較空閒的時候做

這樣的操作叫做Write Ahead Logging,他的關鍵在於先寫日誌,再寫磁碟

寫日誌也是在磁碟上的寫操作,為什麼比直接在磁碟持久化資料高效?
WAL是順序寫入的,也就是一直在檔案末尾append,而持久化資料庫的資料是一個隨機寫入的操作,順序寫會節省大量磁碟懸臂來回定址的過程,效率更高

現在是否還需要WAL?
現在都用SSD而不在使用HARD,SSD沒有機械結構,無需尋道,那麼上面所說的優點是否就不存在了?

2.3 redo-log的結構

InnoDB 的 redo log 是固定大小的,比如可以配置為一組 4 個檔案,每個檔案的大小是 1GB,那麼這塊“粉板”總共就可以記錄 4GB 的操作。從頭開始寫,寫到末尾就又回到開頭迴圈寫
在這裡插入圖片描述

  • write pos 是當前記錄的位置,一邊寫一邊後移,寫到第 3 號檔案末尾後就回到 0 號檔案開頭
  • checkpoint 是當前要擦除的位置,也是往後推移並且迴圈的,擦除記錄前要把記錄更新到資料檔案
  • write poscheckpoint 之間的是“粉板”上還空著的部分,可以用來記錄新的操作。如果 write pos 追上 checkpoint,表示“粉板”滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把 checkpoint 推進一下

2.4 crash-safe

有了 redo log,InnoDB 就可以保證即使資料庫發生異常重啟,之前提交的記錄都不會丟失,當資料庫發生宕機重啟後,可以通過redo log將未落盤的資料恢復,這個能力稱為 crash-safe

2.5 redo log是如何保證crash safe

每條 redolog 都有兩個狀態 – prepare 與 commit 狀態

例如對於一張 mysql 表

(CREATE TABLE `A` (`ID` int(10) unsigned NOT NULL AUTO_INCREMENT, `C` int(10) NOT NULL DEFAULT 0, PRIMARY KEY (`ID`)) ENGINE=InnoDB)

我們執行一條 SQL 語句:

mysql> update T set c=c+1 where ID=2
  1. 執行器先找引擎取 ID=2 這一行。ID 是主鍵,引擎直接用樹搜尋找到這一行。如果 ID=2 這一行所在的資料頁本來就在記憶體中,就直接返回給執行器;否則,需要先從磁碟讀入記憶體,然後再返回。
  2. 執行器拿到引擎給的行資料,把這個值加上 1,比如原來是 N,現在就是 N+1,得到新的一行資料,再呼叫引擎介面寫入這行新資料。
  3. 引擎將這行新資料更新到記憶體中,同時將這個更新操作記錄到 redo log 裡面,此時 redo log 處於 prepare 狀態。然後告知執行器執行完成了,隨時可以提交事務。
  4. 執行器生成這個操作的 binlog,並把 binlog 寫入磁碟。
  5. 執行器呼叫引擎的提交事務介面,引擎把剛剛寫入的 redo log 改成提交(commit)狀態,更新完成

在這裡插入圖片描述
(圖中淺色框表示是在InnoDB內部執行的,深色框表示在執行器中執行的)

可以看到,在寫入 binlog 及事務提交前,innodb 先記錄了 redolog,並標記為 prepare 狀態,在事務提交後,innodb 會將 redolog 更新為 commit 狀態,這樣在異常發生時,就可以按照下面兩條策略來處理:

  1. 當異常情況發生時,如果第一次寫入 redolog 成功,寫入 binlog 失敗,MySQL 會當做事務失敗直接回滾,保證了後續 redolog 和 binlog 的準確性
  2. 如果第一次寫入 redolog 成功,binlog 也寫入成功,當第二次寫入 redolog 時候失敗了,那資料恢復的過程中,MySQL 判斷 redolog 狀態為 prepare,且存在對應的 binlog 記錄,則會重放事務提交,資料庫中會進行相應的修改操作