一、日志類型
-
邏輯日志:存儲了邏輯SQL修改語句
-
物理日志:存儲了數據被修改的值
二、binlog
1.定義
binlog 是 MySQL 的邏輯日志,也叫二進制日志、歸檔日志,由 MySQL Server 來記錄。
用於記錄用戶對數據庫操作的SQL語句(除了查詢語句)信息,以二進制的形式保存在磁盤中。
2.記錄方式
binlog 通過追加的方式寫入的,可通過配置參數 max_binlog_size 設置每個 binlog 文件的大小,當文件大小大於給定值后,日志會發生滾動,之后的日志記錄到新的文件上。
3.格式
binlog 日志有三種格式,分別為 STATMENT、ROW 和 MIXED。
|
STATMENT
|
ROW
|
說明
|
基於SQL語句的復制(statement-based replication, SBR),每一條會修改數據的sql語句會記錄到binlog中。
是bin log的默認格式。
|
基於行的復制(row-based replication, RBR):不記錄每一條SQL語句的上下文信息,僅保存哪條記錄被修改。
|
優點
|
不需要記錄每一條SQL語句與每行的數據變化,減少了bin log的日志量,節約了磁盤IO,提高性能。
|
會非常清楚的記錄下每一行數據修改的細節,不會出現某些特定情況下的存儲過程、或function、或trigger的調用和觸發無法被正確復制的問題。
|
缺點
|
在某些情況下會導致master-slave中的數據不一致,如sleep()函數, last_insert_id(),以及user-defined functions(udf)等會出現問題。
|
會產生大量的日志,尤其是alter table的時候會讓日志暴漲。
|
MIXED模式是基於 STATMENT 和 ROW 兩種模式的混合復制(mixed-based replication, MBR),一般的復制使用STATEMENT模式保存 binlog,對於 STATEMENT 模式無法復制的操作使用ROW模式保存 binlog,MySQL 會根據執行的 SQL 語句選擇日志保存方式。
三、redo log
1.定義:
redo log 是 MySQL 的物理日志,也叫重做日志,記錄存儲引擎 InnoDB 的事務日志。
MySQL 每執行一條 SQL 更新語句,不是每次數據更改都立刻寫到磁盤,而是先將記錄寫到 redo log 里面,並更新內存(這時內存與磁盤的數據不一致,將這種有差異的數據稱為臟頁),一段時間后,再一次性將多個操作記錄寫到到磁盤上,這樣可以減少磁盤 io 成本,提高操作速度。
先寫日志,再寫磁盤,這就是 MySQL 里經常說到的 WAL 技術,即 Write-Ahead Logging,又叫預寫日志。MySQL 通過 WAL 技術保證事務的持久性。
2.記錄方式
InnoDB 的 redo log 大小是固定的,采用循環寫的方式記錄,當寫到結尾時,會回到開頭循環寫日志。如下圖:

write pos表示日志當前記錄的位置,當ib_logfile_4寫滿后,會從ib_logfile_1從頭開始記錄;
check point表示將日志記錄的修改寫進磁盤,完成數據落盤,數據落盤后check point會將日志上的相關記錄擦除掉,
即write pos->check point之間的部分是redo log空着的部分,用於記錄新的記錄,check point->write pos之間是redo log待落盤的數據修改記錄。當write pos追上check point時,得先停下記錄,先推動check point向前移動,空出位置記錄新的日志。
有了 redo log,當數據庫發生宕機重啟后,可通過 redo log 將未落盤的數據(check point之后的數據)恢復,保證已經提交的事務記錄不會丟失,這種能力稱為crash-safe。
四、兩階段提交
有了 redo log,為什么還需要 binlog 呢?先來看看 binlog 和redo log 的區別:
|
redo log
|
binlog
|
文件大小
|
redo log 的大小是固定的。
|
binlog 可通過配置參數max_binlog_size 設置每個 binlog 文件的大小。
|
實現方式
|
redo log 是 InnoDB 引擎層實現的,並不是所有引擎都有。
|
binlog是 Server 層實現的,所有引擎都可以使用 binlog 日志。
|
記錄方式
|
redo log 采用循環寫的方式記錄,當寫到結尾時,會回到開頭循環寫日志。日志上的記錄修改落盤后,日志會被覆蓋掉,無法用於數據回滾/數據恢復等操作。
|
binlog 通過追加的方式記錄,當文件大小大於給定值后,日志會發生滾動,之后的日志記錄到新的文件上,不會覆蓋以前的記錄。
|
由 binlog 和 redo log 的區別可知:binlog 日志只用於歸檔,只依靠 binlog 是沒有 crash-safe 能力的。但只有 redo log 也不行,因為 redo log 是InnoDB 特有的,且日志上的記錄落盤后會被覆蓋掉。因此需要 binlog 和 redo log 二者同時記錄,才能保證當數據庫發生宕機重啟時,數據不會丟失。
當執行一條 SQL 更新語句時,過程如下:

可以看到,在“兩階段提交”階段,將 redo log 的寫入分成了兩步:prepare 和 commit。在 redo log 狀態為 prepare 時記錄 binlog 可以保證兩個日志的記錄一致。
五、如果數據庫誤操作, 如何執行數據恢復?
DB宕機后重啟,InnoDB 會首先去查看數據頁中的LSN的數值。這個值代表數據頁被刷新回磁盤的 LSN 的大小。然后再去查看 redo log 的 LSN 的大小。
如果數據頁中的 LSN 值大說明數據頁領先於 redo log 刷新回磁盤,不需要進行恢復。反之需要從redo log中恢復數據。
注:LSN 是 日志序列號, 為 log sequence number 的縮寫,主要用於發生 crash 時對數據進行 recovery。LSN是一個一直遞增的整型數字,表示事務寫入到日志的字節總量。
LSN 不僅只存在於重做日志中,在每個數據頁頭部也會有對應的 LSN 號,該 LSN 記錄當前頁最后一次修改的 LSN 號,用於在 recovery 時對比重做日志 LSN 號決定是否對該頁進行恢復數據。
前面說的check point也是由 LSN 號記錄的,LSN 號串聯起一個事務開始到恢復的過程。
如果將 innodb_flush_log_at_trx_commit 和 sync_binlog 參數設置成 1,前者表示每次事務的 redo log 都直接持久化到磁盤,后者表示每次事務的 binlog 都直接持久化到磁盤,可以雙重保證 MySQL 異常重啟之后的數據不會丟失。
原文:https://www.cnblogs.com/sunshineliulu/p/10905483.html