為什么 redo log 具有 crash-safe 的能力,是 binlog 無法替代的?


昨天在復習 MySQL 日志相關的知識,學的東西過一段時間后就會遺忘,遺忘后再重新思考,往往會有新的收獲。想到幾個問題,把它記錄下來。

為什么 redo log 具有 crash-safe 的能力,而 binlog 沒有?

redo log 是什么?

一個固定大小,“循環寫”的日志文件,記錄的是物理日志——“在某個數據頁上做了某個修改”。

binlog 是什么?

一個無限大小,“追加寫”的日志文件,記錄的是邏輯日志——“給 ID=2 這一行的 c 字段加1”。

redo log 和 binlog 有一個很大的區別就是,一個是循環寫,一個是追加寫。也就是說 redo log 只會記錄未刷盤的日志,已經刷入磁盤的數據都會從 redo log 這個有限大小的日志文件里刪除。binlog 是追加日志,保存的是全量的日志。

當數據庫 crash 后,想要恢復未刷盤但已經寫入 redo log 和 binlog 的數據到內存時,binlog 是無法恢復的。雖然 binlog 擁有全量的日志,但沒有一個標志讓 innoDB 判斷哪些數據已經刷盤,哪些數據還沒有。

舉個栗子,binlog 記錄了兩條日志:

  1. 給 ID=2 這一行的 c 字段加1
  2. 給 ID=2 這一行的 c 字段加1

在記錄1刷盤后,記錄2未刷盤時,數據庫 crash。重啟后,只通過 binlog 數據庫無法判斷這兩條記錄哪條已經寫入磁盤,哪條沒有寫入磁盤,不管是兩條都恢復至內存,還是都不恢復,對 ID=2 這行數據來說,都不對。

但 redo log 不一樣,只要刷入磁盤的數據,都會從 redo log 中抹掉,數據庫重啟后,直接把 redo log 中的數據都恢復至內存就可以了。這就是為什么 redo log 具有 crash-safe 的能力,而 binlog 不具備。

當數據庫 crash 后,如何恢復未刷盤的數據到內存中?

根據 redo log 和 binlog 的兩階段提交,未持久化的數據分為幾種情況:

  1. change buffer 寫入,redo log 雖然做了 fsync 但未 commit,binlog 未 fsync 到磁盤,這部分數據丟失。
  2. change buffer 寫入,redo log fsync 未 commit,binlog 已經 fsync 到磁盤,先從 binlog 恢復 redo log,再從 redo log 恢復 change buffer。
  3. change buffer 寫入,redo log 和 binlog 都已經 fsync,直接從 redo log 里恢復。

(全文完)

本文首發於我的個人博客 https://chaohang.top
作者 張超航,公眾號【超超不會飛】
轉載本站文章請注明作者和出處 超超不會飛 ,請勿用於任何商業用途

歡迎關注我的微信公眾號 【超超不會飛】,獲取第一時間的更新。


免責聲明!

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



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