天天看點

mysql日志系統binlog,redolog,undolog

總結下重做日志(redo log)、復原日志(undo log)、二進制日志(binlog)的概念。

redo log 是實體日志,undo log 和 binlog 是邏輯日志

binlog二進制日志是server層的無論MySQL用什麼引擎,都會有的,主要是左主從複制,時間點恢複使用

redo log重做日志是InnoDB存儲引擎層的,用來保證事務安全

undo log復原日志儲存了事務發生之前的資料的一個版本,可以用于復原,同時可以提供多版本并發控制下的讀(MVCC),也即非鎖定讀

InnoDB 就可以保證即使資料庫發生異常重新開機,之前送出的記錄都不會丢失,這個能力稱為 crash-safe。

舉個列子:當我們修改的時候,寫完記憶體了(buffer),但資料還沒真正寫到磁盤的時候。此時我們的資料庫挂了,我們可以對資料進行恢複

redo log 是實體日志,記載着每次在某個頁上做了什麼修改。寫redo log也是需要寫磁盤的,但它的好處就是順序IO(我們都知道順序IO比随機IO快非常多)。寫入的速度很快

事務開始之後,就開始産生 redo log 日志了,在事務執行的過程中,redo log 開始逐漸落盤

當對應事務的髒頁寫入到磁盤之後,redo log 的使命就完成了,它所占用的空間也就可以被覆寫了。

InnoDB 的 redo log 是固定大小的,比如可以配置為一組 4 個檔案,每個檔案的大小是 1GB。從頭開始寫,寫到末尾就又回到開頭循環寫

mysql日志系統binlog,redolog,undolog

write pos 是目前記錄的位置,一邊寫一邊後移,寫到第 3 号檔案末尾後就回到 0 号檔案開頭。checkpoint 是目前要擦除的位置,也是往後推移并且循環的,擦除記錄前要把記錄更新到資料檔案。

write pos 和 checkpoint 之間的的部分,可以用來記錄新的操作。如果 write pos 追上 checkpoint,表示“粉闆”滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把 checkpoint 推進一下。

redo log 包括兩部分:

一是記憶體中的日志緩沖(redo log buffer),該部分日志是易失性的;

二是磁盤上的重做日志檔案(redo log file),該部分日志是持久的,redo log 存儲的是實體格式的日志,記錄的是實體資料頁面的修改資訊,它是順序寫入 redo log file 中的。

Master Thread 每秒一次執行重新整理 Innodb_log_buffer 到重做日志檔案

每個事務送出時會将重做日志重新整理到重做日志檔案

當重做日志緩存可用空間少于一半時,重做日志緩存被重新整理到重做日志檔案

其實寫redo log的時候,也會有buffer,是先寫buffer,再真正落到磁盤中的。至于從buffer什麼時候落磁盤,會有配置供我們配置。

redo log 是 InnoDB 引擎特有的日志

持久性就是靠redo log來實作的(如果寫入記憶體成功,但資料還沒真正刷到磁盤,如果此時的資料庫挂了,我們可以靠redo log來恢複記憶體的資料,這就實作了持久性)。

u儲存了事務發生之前的資料的一個版本,作用:

可以用于復原

同時可以提供多版本并發控制下的讀(MVCC),也即非鎖定讀

事務開始之前,将目前事務版本生成 undo log,undo log 也會産生 redo log 來保證 undo log 的可靠性。

當事務送出之後,undo log 并不能立馬被删除,而是放入待清理的連結清單,

由 purge 線程判斷是否有其它事務在使用 undo 段中表的上一個事務之前的版本資訊,進而決定是否可以清理 undo log 的日志空間。

undo log 存儲的是邏輯格式的日志,儲存了事務發生之前的上一個版本的資料,可以用于復原。當一個舊的事務需要讀取資料時,為了能讀取到老版本的資料,需要順着 undo 鍊找到滿足其可見性的記錄。

預設情況下,undo 檔案是儲存在共享表空間的,也即 ibdatafile 檔案中,當資料庫中發生一些大的事務性操作的時候,要生成大量的 undo log 資訊,這些資訊全部儲存在共享表空間中,是以共享表空間可能會變得很大,預設情況下,也就是 undo log 使用共享表空間的時候,被“撐大”的共享表空間是不會、也不能自動收縮的。是以,MySQL5.7 之後的“獨立 undo 表空間”的配置就顯得很有必要了。

binlog我們可以簡單了解為:存儲着每條變更的SQL語句

可以通過binlog來對資料進行恢複

binlog 可以用于主從複制中,從庫利用主庫上的 binlog 進行重播,實作主從同步。用于資料庫的基于時間點、位點等的還原操作。binlog 的模式分三種:Statement、Row、Mixed。

每一條修改資料的 sql 都會記錄到 master 的 binlog 中,slave 在複制的時候,sql 程序會解析成和原來在 master 端執行時的相同的 sql 再執行。

優點:在 statement 模式下首先就是解決了 row 模式的缺點,不需要記錄每一行資料的變化,進而減少了 binlog 的日志量,節省了 I/O 以及存儲資源,提高性能。因為它隻需要記錄在 master 上執行的語句的細節以及執行語句的上下文資訊。

缺點:在 statement 模式下,由于它是記錄的執行語句,是以,為了讓這些語句在 slave 端也能正确執行,那麼它還必須記錄每條語句在執行的時候的一些相關資訊,即上下文資訊,以保證所有語句在 slave 端和在 master 端執行結果相同。另外就是,由于 MySQL 現在發展比較快,很多新功能不斷的加入,使 MySQL 的複制遇到了不小的挑戰,自然複制的時候涉及到越複雜的内容,bug 也就越容易出現。在statement 中,目前已經發現不少情況會造成 MySQL 的複制出現問題,主要是在修改資料的時候使用了某些特定的函數或者功能才會出現,比如:sleep() 函數在有些版本中就不能被正确複制,在存儲過程中使用了 last_insert_id() 函數,可能會使 slave 和 master 上得到不一緻的 id 等等。由于 row 模式是基于每一行來記錄變化的,是以不會出現類似的問題。

日志中會記錄每一行資料被修改的形式,然後在 slave 端再對相同的資料進行修改。row 模式隻記錄要修改的資料,隻有 value,不會有 sql 多表關聯的情況。

優點:在 row 模式下,binlog 中可以不記錄執行的 sql 語句的上下文相關的資訊,僅僅隻需要記錄哪一條記錄被修改了,修改成什麼樣了,是以 row 的日志内容會非常清楚的記錄下每一行資料的修改細節,非常容易了解。而且不會出現某些特定情況下的存儲過程和 function,以及 trigger 的調用和觸發無法被正确複制問題。

缺點:在 row 模式下,當所有執行語句記錄到日志中的時候,都将以每行記錄的修改來記錄,這樣可能會産生大量的日志内容。

從官方文檔中看到,之前的 MySQL 一直都隻有基于 statement 的複制模式,直到 5.1.5 版本的 MySQL 才開始支援 row 複制。從 5.0 開始,MySQL 的複制已經解決了大量老版本中出現的無法正确複制的問題。但是由于存儲過程的出現,給 MySQL Replication 又帶來了更大的新挑戰。另外,看到官方文檔說,從 5.1.8 版本開始,MySQL 提供了除 Statement 和 Row 之外的第三種複制模式:Mixed,實際上就是前兩種模式的結合。在 Mixed 模式下,MySQL 會根據執行的每一條具體的 SQL 語句來區分對待記錄的日志形式,也就是在 statement 和 row 之間選擇一種。新版本中的 statment 還是和以前一樣,僅僅記錄執行的語句。而新版本的 MySQL 也對 row 模式做了優化,并不是所有的修改都會以 row 模式來記錄,比如遇到表結構變更的時候就會以 statement 模式來記錄,如果 SQL 語句确實就是 update 或者 delete 等修改資料的語句,那麼還是會記錄所有行的變更。

事務送出的時候,一次性将事務中的 sql 語句(一個事務可能對應多個 sql 語句)按照一定的格式記錄到 binlog 中,這裡與 redo log 很明顯的差異就是 redo log 并不一定是在事務送出的時候才重新整理到磁盤,而是在事務開始之後就開始逐漸寫入磁盤。binlog 的預設儲存時間是由參數 expire_logs_days 配置的,對于非活動的日志檔案,在生成時間超過 expire_logs_days 配置的天數之後,會被自動删除。

MySQL通過兩階段送出來保證redo log和binlog的資料是一緻的

update 語句的執行流程圖,圖中淺色框表示是在 InnoDB 内部執行的,深色框表示是在執行器中執行的

mysql日志系統binlog,redolog,undolog

 将 redo log 的寫入拆成了兩個步驟:prepare 和 commit,這就是"兩階段送出"。

參考:http://xiaot123.com/mysqlbinlogredologundolog-lagwx