日志是數(shù)據(jù)庫中比較重要的組成部分,很多核心的功能必須依靠日志才能完成。
該篇文章簡要介紹了binlog、redo log與undo log,能夠在一定程度上拓寬對mysql日志的整體認識。
binlog
又稱歸檔日志,由Server層實現(xiàn)與記錄,因此對任何引擎都有效。
binlog是一種只記錄對表中數(shù)據(jù)以及對表結(jié)構(gòu)產(chǎn)生更改操作的二進制文件,比如有insert、update、delete、create table、alter table等操作,不記錄select、show,因為這些操作不會產(chǎn)生任何更改。不過就算一個update未產(chǎn)生數(shù)據(jù)變化,也是會被記錄進去的。
你可以理解binlog是直接記錄sql語句,或者說記錄原始sql邏輯,因此binlog屬于邏輯日志。
binlog是追加寫入的,一個文件寫滿,會重新創(chuàng)建一個文件繼續(xù)寫,文件名稱是mysql-bin.xxxxxx,例如myql-bin.000001,序號部分會遞增。
binlog的格式
binlog有三種格式,可以通過binlog-format來設定
直接記錄操作的sql語句,例如update student set name='tom' where id=1;
優(yōu)點:
這種格式的binlog,可以直接進行閱讀。
不記錄具體的行數(shù)據(jù),日志量不會很大,性能較優(yōu)。
缺點:
當binlog用于主從之間的復制時,如果當前的sql語句為隨機函數(shù)rand()、當前日期now()等,在重現(xiàn)之后具有不同的值,具有歧義性,可能會造成復制后數(shù)據(jù)不一致。
ROW
對于update student set name='tom' where id=1操作,會記錄id=1這條數(shù)據(jù)中name字段在修改前與修改后的數(shù)據(jù)。
優(yōu)點:
準確性強
缺點:
可讀性差,需要借助解析。
如果經(jīng)常修改一些字段比較長的數(shù)據(jù),會造成生成的binlog日志量變多,性能稍弱。
當然,alter table等直接改變表結(jié)構(gòu)的語句,也會快速增加日志量與磁盤IO。
MIXED
其實就是一種對與ROW的混合使用方式
對不會造成歧義的操作使用格式進行記錄,否則使用ROW格式記錄。
對表結(jié)構(gòu)的修改操作,也使用ROW格式進行記錄。
不過,比較推薦的是ROW格式,特別是在SSD、云端存儲、大帶寬普及的今天,這點兒的存儲空間與磁盤IO還是吃得消的,滴滴基于Binlog的采集架構(gòu)就是直接使用的ROW格式。
binlog的使用場景 主從復制
當我們使用主從結(jié)構(gòu)的mysql時,從庫需要同步主庫的數(shù)據(jù)。
這個時候主庫會將自己的binlog異步發(fā)送給從庫,從庫在本地完成sql回放,來達到主從數(shù)據(jù)一致的目的。
主從復制之間可能會存在延遲,當主庫只負責寫,從庫只負責讀時,寫完主庫之后的立馬讀從庫,可能會出現(xiàn)問題。
關于主從復制原理及主從延遲的解決方案,會另開篇幅。
數(shù)據(jù)恢復
當誤刪生產(chǎn)數(shù)據(jù)時,可以通過binlog來恢復。
找到生產(chǎn)庫最近的一次全量備份,首先由全量備份恢復到臨時庫中。
接著從全量備份的時間點開始,重放binlog一直到mysql不產(chǎn)生新的binlog為止,另外要注意刪除binlog中誤操作的語句,最后切換臨時庫為生產(chǎn)庫。
值得注意的一點是,binlog默認是不開啟的。
redo log
又稱重做日志,是Innodb引擎中特有的日志。如果當前使用的引擎是Myisam或者Memory,那就無從談起redo log。
和binlog的內(nèi)容不同,redo log記錄了“在某個數(shù)據(jù)頁上做了哪些修改”,屬于物理日志。
為什么要有redo log?
Innodb引擎是以頁為單位來和磁盤交互的,一般來說,如果一個事務提交后,需要將修改后的數(shù)據(jù)頁寫回到磁盤中。
如果本次事務只修改當前數(shù)據(jù)頁中的幾個Byte,直接將當前數(shù)據(jù)頁的所有內(nèi)容刷到磁盤后,涉及到大量的隨機寫,IO成本很高,性能比較低。
如果事務提交后,先將“對哪個數(shù)據(jù)頁做了哪些修改”順序?qū)懭雛edo log,之后會在合適的時機寫回到buffer pool(你可以把buffer pool理解為緩沖池,如果查詢到一條記錄時,會將記錄所在的數(shù)據(jù)頁加載進緩沖池中。之后再進行查找時,先查詢緩沖池,查不到再查磁盤,查到了就再放入到緩沖池中。這樣做,在一定程度上可以減少IO成本,提升性能)中,最后將buffer pool中的數(shù)據(jù)頁刷盤,在一定程度上可以減少IO成本。
此外,binlog是不支持crash-safe,即崩潰恢復的,只是支持誤刪數(shù)據(jù)恢復。當redo log與binlog結(jié)合在一起的時候,光芒就出現(xiàn)了,此處應該有迪迦。redo log中較實際數(shù)據(jù)頁中多出來的那部分日志,就是崩潰后用于恢復的日志。
redo log的記錄方式
和binlog追加寫不同,redo log采用的是循環(huán)寫。之所以用循環(huán)寫,是因為之前恢復的數(shù)據(jù)再保存在redo log中就沒有任何意義了。
假設redo log最終會寫入到4個文件中,每個文件的大小都是1GB,則此時能夠記錄的最大日志量為4GB。
比如先從1號文件中寫入,寫滿之后,就換到2號文件中。4個文件全部寫滿后,再回到1號文件從頭繼續(xù)寫。
這里還有兩個指針,write 與check point
write
指向redo log的記錄進度,write 指針走過的區(qū)域,代表著redo log的日志量逐漸增長。
check point
指向數(shù)據(jù)頁刷盤后的恢復進度,check point指針走過的區(qū)域,會將區(qū)域內(nèi)redo log數(shù)據(jù)用于恢復,接著將redo log擦除。
兩個指針的運動方向,都是順時針方向。
因此,從write 順時針到check point之間的區(qū)域,都是空著的部分。
當redo log記錄過快時,write 可能會追趕上check point。此時就需要停止redo log記錄,并將所有文件中的redo log恢復。
在這里,有必要總結(jié)一下binlog與redo log的區(qū)別。
binlog與redo log的區(qū)別 log
日志歸屬
由Server層實現(xiàn),所有的引擎都可以使用
Innodb引擎中特有的日志
日志類型
邏輯日志,記錄原始的sql邏輯或數(shù)據(jù)變更的前后內(nèi)容
物理日志,記錄在哪個數(shù)據(jù)頁上進行了哪些更改
寫入方式
追加寫,寫滿則創(chuàng)建一個新文件繼續(xù)寫
循環(huán)寫,全部寫滿就從頭開始
適用場景
主從同步與誤刪恢復
崩潰恢復
在一條類型為update的sql語句的執(zhí)行背后,涉及到binglog與redo log的兩階段提交,這個也會另開篇幅。
Undo log
undo log主要用于事務回滾時恢復原來的數(shù)據(jù)
mysql在執(zhí)行sql語句時,會將一條邏輯相反的日志保存到undo log中。因此,undo log中記錄的也是邏輯日志。
當sql語句為insert時,會在undo log中記錄本次插入的主鍵id。等事務回滾時,delete此id即可。
當sql語句為update時,會在undo log中記錄修改前的數(shù)據(jù)。等事務回滾時,再執(zhí)行一次update,得到原來的數(shù)據(jù)。
當sql語句為delete時,會在undo log中記錄刪除前的數(shù)據(jù)。等事務回滾時,insert原來的數(shù)據(jù)即可。
數(shù)據(jù)庫事務四大特性中的原子性,即事務具有不可分割性,要么全部成功,要么全部失敗,其底層就靠undo log實現(xiàn)。在某一步執(zhí)行失敗時,會對之前事務的語句進行回滾。
另外,undo log與合作可以實現(xiàn)多版本并發(fā)控制MVCC(Mutil-Version Control)。
MVCC
對于MVCC,簡單來講,就是mysql保存了一行數(shù)據(jù)在多個時間點的快照,是一種使用空間換取時間的策略,能做到讀(快照讀,可以理解就是普通的select語句)寫不加鎖。
你可以暫時理解為,每一份快照包含了一行undo log日志,各個版本的快照通過指針連接起來,這樣可以順著指針快速找到上一份快照。
(圖片來源于互聯(lián)網(wǎng),聯(lián)系侵刪)
關于MVCC實現(xiàn)原理,也會另開篇幅。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。