what:
崩潰恢復:即使在數據庫宕機的情況下,也不會出現操作一半的情況;
bin log :是server層的歸檔日志,不足以實現崩潰恢復(crash-safe);
redo log :是物理日志,具有崩潰恢復的能力;
diff:
1、適用對象:
bin log: 是 MySQL 的 Server 層實現的,所有引擎都可以使用;
redo log :是 InnoDB 引擎特有的;
2、寫入內容:
bin log:是邏輯日志。記錄的是這個語句的原始邏輯,比如 “給 id = 1 這一行的 age 字段加 1”;
redo log :是物理日志。記錄的是 “在某個數據頁上做了什么修改”;
3、寫入方式:
bin log:是追加寫入。“追加寫” 是指 bin log 文件寫到一定大小后會切換到下一個,並不會覆蓋以前的日志。那么就會出現“沒有標志能讓 InnoDB 從 bin log 中判斷哪些數據已經刷入磁盤了,哪些數據還沒有”;
redo log :是循環寫入。即空間固定會被用完;那么“只會記錄未刷入磁盤的日志,已經刷入磁盤的數據就會刪掉”;
how:
核心方案:redo log采用兩階段提交。即redo log的寫入拆分為了2個步驟:prepare和commit;
SQL 查詢語句的執行過程:(具體流程入下圖)
1、MySQL 客戶端與服務器間建立連接,客戶端發送一條查詢給服務器;
2、服務器先檢查查詢緩存,如果命中了緩存,則立刻返回存儲在緩存中的結果;否則進入下一階段;
3、服務器端進行 SQL 解析、預處理,生成合法的解析樹;
4、由優化器生成對應的執行計划;
5、執行器根據執行計划(優化器生成),調用相應的存儲引擎的 API 來執行,並將執行結果返回給客戶端;
SQL更新語句的執行過程:相對查詢多了,兩日志模塊 bin log 和 redo log的操作。
以“update tablese tage=age+1 where id=1;”為栗子:
注意:以下操作和查詢的前4步相同。
1、執行器:找存儲引擎取到 id = 1 這一行記錄;
2、存儲引擎:根據主鍵索引樹找到這一行,如果 id = 1 這一行所在的數據頁本來就在內存池(Buffer Pool)中,就直接返回給執行器;否則,需要先從磁盤讀入內存池,然后再返回;
3、執行器:拿到存儲引擎返回的行記錄,把 age 字段加上 1,得到一行新的記錄,然后再調用存儲引擎的接口寫入這行新記錄;
4、存儲引擎:將這行新數據更新到內存中,同時將這個更新操作記錄到 redo log 里面,此時 redo log 處於 prepare
狀態。然后告知執行器執行完成了,隨時可以提交事務;
注意:此處的“事務”是提交過程中的一個小步驟,也是最后一步,而非 sql 語句中的提交事務 commit 命令
5、執行器:生成這個操作的 bin log,並把 bin log 寫入磁盤;
6、執行器:調用存儲引擎的提交事務接口;
7、存儲引擎:把剛剛寫入的 redo log 狀態改成提交(commit
)狀態,更新完成;
具體如下圖:
why():
怎么判斷bin log 是不是完整的?
1、statement 格式的 bin log,最后會有 COMMIT;
2、row 格式的 bin log,最后會有 XID event;
3、對於 bin log 可能會在中間出錯的情況,MySQL 5.6.2 版本以后引入了 binlog-checksum
參數,用來驗證 bin log 內容的正確性;
為何redo log有崩潰恢復能力?
1、如果 redo log 里面的事務是完整的,也就是已經有了 commit 標識,則直接提交;
2、如果 redo log 里面的事務處於 prepare 狀態,則判斷對應的事務 binlog 是否存在並完整
a、如果 binlog 存在並完整,則提交事務;
b、否則,回滾事務;
栗子1:“數據庫在寫入 redo log(prepare) 階段之后、寫入 binlog 之前,發生了崩潰”。
分析:此時,redo log處於prepare狀態,但是binlog沒有完成,事務就需要回歸。
原因:binlog 還沒有寫入,之后從庫進行同步的時候,就會缺少數據,但是主庫中已經有數據了,結果就是“主從不一致”,所以主庫的操作需要回滾。
栗子2:“數據庫在寫入 binlog 之后,redo log在commit之前發生了崩潰”。圖如下:
分析:redo log處於prepare狀態,binlog完整了,事務直接提交。
原因: binlog 寫入成功,從庫能夠同步過去。此時主庫並沒有完成這個操作,所以主備就不一致了。那么在主庫上需要提交這個事務。