MySQL redo與undo日誌解析
前言:
前面文章講述了 MySQL 系統中常見的幾種日誌,其實還有事務相關日誌 redo log 和 undo log 沒有介紹。相對於其他幾種日誌而言, redo log 和 undo log 是更加神祕,難以觀測的。本篇文章將主要介紹這兩類事務日誌的作用及運維方法。
1.重做日誌(redo log)
我們都知道,事務的四大特性裡面有一個是 永續性
,具體來說就是隻要事務提交成功,那麼對資料庫做的修改就被永久儲存下來了,不可能因為任何原因再回到原來的狀態。那麼 MySQL 是如何保證一致性的呢?最簡單的做法是在每次事務提交的時候,將該事務涉及修改的資料頁全部重新整理到磁碟中。但是這麼做會有嚴重的效能問題,主要體現在兩個方面:
- 因為 Innodb 是以頁為單位進行磁碟互動的,而一個事務很可能只修改一個數據頁裡面的幾個位元組,這個時候將完整的資料頁刷到磁碟的話,太浪費資源了。
- 一個事務可能涉及修改多個數據頁,並且這些資料頁在物理上並不連續,使用隨機 IO 寫入效能太差。
因此 MySQL 設計了 redo log
,具體來說就是隻記錄事務對資料頁做了哪些修改,這樣就能完美地解決效能問題了(相對而言檔案更小並且是順序IO)。
redo log 包括兩部分:一個是記憶體中的日誌緩衝(redo log buffer),另一個是磁碟上的日誌檔案(redo log file)。MySQL 每執行一條 DML 語句,先將記錄寫入 redo log buffer ,後續某個時間點再一次性將多個操作記錄寫到 redo log file 。
預設情況下,redo log 在磁碟上由名為 ib_logfile0
和 ib_logfile1
的兩個物理檔案展示。redo log 相關引數簡單介紹如下:
- innodb_log_files_in_group:redo log 檔案的個數,命名方式如:ib_logfile0,iblogfile1... iblogfilen。預設2個,最大100個。
- innodb_log_file_size:單個 redo log 檔案設定大小,預設值為 48M,最大值為512G,注意最大值指的是整個 redo log 系列檔案之和,即(innodb_log_files_in_group * innodb_log_file_size )不能大於最大值512G。
- innodb_log_group_home_dir:指定 redo log 檔案組所在的路徑,預設./ ,表示在資料庫的資料目錄下。
- innodb_log_buffer_size:redo log buffer 大小,預設16M。延遲事務日誌寫入磁碟,把 redo log 放到該緩衝區,然後根據 innodb_flush_log_at_trx_commit 引數的設定,再把日誌從 buffer 中 flush 到磁碟中。
- innodb_flush_log_at_trx_commit:控制 redo log 重新整理到磁碟的策略,預設為1。值為1,每次 commit 都會把 redo log 從 redo log buffer 寫入到 system ,並 fsync 重新整理到磁碟檔案中。值為2,每次事務提交時 MySQL 會把日誌從 redo log buffer 寫入到 system ,但只寫入到 file system buffer,由系統內部來 fsync 到磁碟檔案。如果資料庫例項 crash ,不會丟失 redo log,但是如果伺服器 crash,由於 file system buffer 還來不及 fsync 到磁碟檔案,所以會丟失這一部分的資料。值為0,表示事務提交時不進行寫入 redo log 操作,這個操作僅在 master thread 中完成,而在 master thread 中每1秒進行一次重做日誌的 fsync 操作,因此例項 crash 最多丟失1秒鐘內的事務。
更改 redo log 及其 buffer 大小是需要重啟資料庫例項的,建議初始化時做好評估。可以適當加大 redo log 組數和大小,特別是你的資料庫例項更新比較頻繁的情況下。但也不推薦 redo log 設定過大。
2.回滾日誌(undo log)
undo log
主要用於保證資料的原子性,儲存了事務發生之前的資料的一個版本,可以用於回滾。比如一條 INSERT 語句,對應一條 DELETE 的 undo log ,對於每個 UPDATE 語句,對應一條相反的 UPDATE 的 undo log ,這樣在發生錯誤時,就能回滾到事務之前的資料狀態。同時,undo log 也是 MVCC (多版本併發控制) 實現的關鍵。
MySQL 5.7 版本中,undo log 預設存放在共享表空間 ibdata 中。也可以在初始化時通過配置引數改成獨立的檔案,簡單介紹幾個 undo log 相關引數:
- innodb_max_undo_log_size:控制最大 undo tablespace 檔案的大小,當啟動了innodb_undo_log_truncate 時,undo tablespace 超過 innodb_max_undo_log_size 閥值時才會去嘗試truncate。該值預設大小為1G,truncate後的大小預設為10M。
- innodb_undo_tablespaces:設定 undo 獨立表空間個數,範圍為0-128,5.7版本預設為0,0表示不開啟獨立undo表空間。該引數只能在最開始初始化 MySQL 例項的時候指定。
- innodb_undo_directory:設定 undo 表空間的存放目錄,預設資料目錄。
- innodb_undo_log_truncate:設定 undo 表空間是否自動截斷回收。該引數生效的前提是,已設定獨立表空間且獨立表空間個數大於等於2個。
undo log 相關引數一般很少改動。MySQL 8.0 預設啟用了獨立表空間,可能 undo log 表空間的大小設定更靈活些。
總結:
本篇文章主要介紹了 redo log 及 undo log 的作用和相關引數設定,文章寫的比較匆忙,如有錯誤,可以留言指出。關於這兩類日誌更深層次的內容,可能筆者功力還不到,未能寫到更加透徹。好了,MySQL 相關日誌的兩篇文章已經寫完了,希望各位能學到一點知識。
參考: