Mysql數(shù)據(jù)庫面試必備之三大log介紹
快,開篇大伙先思考一個問題,MySQL 是怎么保證數(shù)據(jù)不丟失的呢?
其實要保證數(shù)據(jù)不丟失,說白了要具有下面兩種能力:
(1)能恢復(fù)到任何時間點的狀態(tài);
(2)能保證 MySQL 在任何時間段突然宕機重啟,已提交的數(shù)據(jù)不會丟失,未提交完整的數(shù)據(jù)也會自動回滾;
這不就引出來今天要聊的主題了么,實現(xiàn)第一點需要用 bin log,實現(xiàn)第二點需要用 redo log 和 undo log。
了解三大log之前,我們先看一下Mysql數(shù)據(jù)更新的流程:
上面這張圖包含了 redo log、bin log、undo log 三種日志之間的大致關(guān)系,下面進(jìn)入正題。
一、redo log 重做日志(MySQL 存儲引擎 InnoDB 的事務(wù)日志)
我們知道 MySQL 數(shù)據(jù)存在磁盤中,每次讀寫數(shù)據(jù)需做磁盤 IO,并發(fā)場景下性能差。為此 MySQL 引入緩存 Buffer Pool 做優(yōu)化。其包含磁盤中部分?jǐn)?shù)據(jù)頁(page)的映射,來緩解數(shù)據(jù)庫的磁盤壓力。
當(dāng)從數(shù)據(jù)庫讀數(shù)據(jù)時,首先從緩存中讀,緩存中沒有,則從磁盤讀后放入緩存;當(dāng)向數(shù)據(jù)庫寫數(shù)據(jù)時,先向緩存中寫,此時緩存中的數(shù)據(jù)頁數(shù)據(jù)會變更,該數(shù)據(jù)頁叫臟頁,Buffer Pool 中修改完數(shù)據(jù)后會按照設(shè)定的策略再定期刷到磁盤中去,這個過程叫刷臟頁。
那么問題來了,如果 Buffer Pool 中修改的數(shù)據(jù)還沒有及時的刷到磁盤,MySQL 宕機重啟,就會導(dǎo)致數(shù)據(jù)丟失,無法保證事務(wù)的持久性,怎么辦?
redo log 解決了這個問題。就是說數(shù)據(jù)庫在修改數(shù)據(jù)時,會把更新記錄先寫到 redo log 中,再去修改 Buffer Pool 中的數(shù)據(jù),當(dāng)提交事務(wù)時,調(diào)用 fsync 把 redo log 刷入磁盤。至于緩存中更新的數(shù)據(jù)文件何時刷入磁盤,則由后臺線程異步處理。
注意:此時 redo log 的事務(wù)狀態(tài)是 prepare,還未真正提交成功,要等 bin log 日志寫入磁盤完成后才會變?yōu)?commit,事務(wù)才算真正提交成功。
redo log 的寫入方式?
redo log 采用大小固定,循環(huán)寫入的方式,當(dāng)寫滿后,會重新從頭開始循環(huán)寫,類似一個環(huán)狀。這樣設(shè)計原因是 redo log 記錄的是數(shù)據(jù)頁上的修改,如果 Buffer Pool 中數(shù)據(jù)頁已經(jīng)刷到磁盤,這些記錄就失效了,新日志會將這些失效的記錄覆蓋擦除。
注意:redo log 滿了,在擦除之前,要確保這些要被擦除記錄都已經(jīng)刷到磁盤中了。在擦除舊記錄釋放新空間期間,不能再接收新的更新請求,此時 MySQL 性能會下降。因此高并發(fā)情況下,合理調(diào)整 redo log 大小很重要。
crash-safe 能力是什么?
Innodb 引擎有 crash-safe 能力,即事務(wù)提交過程中任何階段,MySQL 宕機重啟后都能保證事務(wù)的完整性,已提交的數(shù)據(jù)不會丟失。這種能力是通過redo log保證的,MySQL 宕機重啟,系統(tǒng)將自動檢查 redo log,將修改還未寫入磁盤的數(shù)據(jù)從 redo log 恢復(fù)到 MySQL 中。
二、undo log 回滾日志(MySQL 存儲引擎 InnoDB 的事務(wù)日志)
undo log 記錄的是數(shù)據(jù)修改之前的狀態(tài),屬于邏輯日志,起到回滾的作用,是保證事務(wù)原子性的關(guān)鍵。
舉個栗子:假如更新 ID=1 記錄的 name 字段,name 原始數(shù)據(jù)為小王,現(xiàn)改 name 為小張,事務(wù)執(zhí)行 update X set name = 小張 where id =1 語句時,先在 undo log 中記錄一條相反邏輯的 update X set name = 小王 where id =1 記錄,這樣當(dāng)某些原因?qū)е率聞?wù)失敗,就可借助 undo log 將數(shù)據(jù)回滾到事務(wù)執(zhí)行前的狀態(tài)。
那么問題來了:同一個事務(wù)的一條記錄被多次修改,難道每次都要把數(shù)據(jù)修改前的狀態(tài)寫 undo log 嗎?
不會,因為 undo log 只記錄事務(wù)開始前數(shù)據(jù)的原始版本,當(dāng)再次對這行數(shù)據(jù)修改時,產(chǎn)生的修改記錄會寫到 redo log。undo log 負(fù)責(zé)回滾,redo log負(fù)責(zé)前滾。
啥是回滾和前滾?
(1)回滾
未提交的事務(wù),即事務(wù)未執(zhí)行 commit。但事務(wù)內(nèi)修改的臟頁中,有一部分已刷盤。此時數(shù)據(jù)庫宕機重啟,需要回滾來將先前那部分已經(jīng)刷盤的臟塊從磁盤上撤銷。
(2)前滾
未完全提交的事務(wù),即事務(wù)已經(jīng)執(zhí)行 commit,但該事務(wù)內(nèi)修改的臟頁中只有一部分?jǐn)?shù)據(jù)被刷盤,另一部分還在 buffer pool,此時數(shù)據(jù)庫宕機重啟,就要用前滾來將未來得及刷盤的數(shù)據(jù)從 redo log 中恢復(fù)出來并刷盤。?
三、bin log 歸檔日志(數(shù)據(jù)庫 Server 層二進(jìn)制邏輯日志、和什么引擎無關(guān))
bin log 記錄了用戶對數(shù)據(jù)庫所有 sql 操作(不包含查詢語句,因為這類操作對數(shù)據(jù)本身沒有修改)。之所以可以稱為歸檔日志,是因為它不會像 redo log 那樣循環(huán)擦除之前的記錄,而是會一直記錄日志。一個 bin log 文件默認(rèn)最大容量1G(可通過 max_binlog_size 參數(shù)修改),單個日志超過最大值則會新創(chuàng)建一個文件繼續(xù)寫。
注意:日志可能是基于事務(wù)來記錄的,而事務(wù)不應(yīng)該跨文件記錄,如果 binlog 日志文件達(dá)到了最大值但剛好事務(wù)還沒有提交,此時則不會創(chuàng)建新文件記錄,而是繼續(xù)增大日志。因此 max_binlog_size 的值和實際的 binlog 文件大小不一定相等。
經(jīng)過上述介紹,binlog 主要用就是主從同步和數(shù)據(jù)庫基于時間點的還原。
那么問題來了,可以沒有 binlog 嗎(有了 redo log 為啥還需要 bin log)?
需要分場景來看:
主從模式下,binlog 是必須的,因為從庫的數(shù)據(jù)同步需要依賴 binlog;
單機模式下,不考慮數(shù)據(jù)庫基于時間點的還原,binlog 就不是必須的,因為有 redo log 就可以保證 crash-safe 能力了;
redo log 的記錄修改落盤后,日志會被覆蓋掉,無法用于數(shù)據(jù)恢復(fù)等操作,redo log 是 innodb 引擎層實現(xiàn)的,并不是所有引擎都有;
redo log 與 bin log 的區(qū)別?
?什么是 redo log 兩階段提交,為什么要這么做?
更新內(nèi)存后引擎層寫 redo log 將狀態(tài)改成 prepare 為提交第一階段,Server 層寫 bin log,將狀態(tài)改成 commit 為提交第二階段。 兩階段提交目的是確保 binl og 和 redo log 數(shù)據(jù)一致性。
如果不是兩階段提交可能會出現(xiàn)什么情況?
1)假設(shè)先寫 redo log 再寫 bin log,即 redo log 沒有 prepare 階段,寫完直接置為commit,然后再寫 bin log。如果寫完 redo log 后還沒寫完 bin log 數(shù)據(jù)庫宕機了,重啟后系統(tǒng)自動用 redo log 恢復(fù),此時會造成磁盤上數(shù)據(jù)頁數(shù)據(jù)比 bin log 上的記錄數(shù)據(jù)多,數(shù)據(jù)不一致。
2)假設(shè)先寫 bin log 再寫 redo log,如果寫完 bin log 沒寫完 redo log 數(shù)據(jù)庫宕機了,那么 bin log 上的記錄就會比磁盤上數(shù)據(jù)頁的記錄多一些,下次用 bin log 恢復(fù)數(shù)據(jù),恢復(fù)后的數(shù)據(jù)和原來的數(shù)據(jù)不一致。
描述一下 redo log 容災(zāi)恢復(fù)過程?
如果 redo log 是完整(commit 狀態(tài))的,直接用 redo log 恢復(fù);
如果 redo log 是預(yù)提交 prepare 但不是 commit 狀態(tài),此時要去判斷 binlog 是否完整,如果完整(commit)那就提交 redo log,再用 redo log 恢復(fù),不完整就回滾事務(wù)。
?到此這篇關(guān)于Mysql數(shù)據(jù)庫面試必備之三大log介紹的文章就介紹到這了,更多相關(guān)Mysql三大log內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于MySQL自增ID的一些小問題總結(jié)
這篇文章主要給大家總結(jié)介紹了關(guān)于MySQL自增ID的一些小問題,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11mysql-connector-java與mysql版本的對應(yīng)關(guān)系說明
這篇文章主要介紹了mysql-connector-java與mysql版本的對應(yīng)關(guān)系說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02重新restore了mysql到另一臺機器上后mysql 編碼問題報錯
重新restore了mysql到另一臺機器上,今天新寫了一個app,發(fā)現(xiàn)在admin界面下一添加漢字就會報錯2011-12-12