天天看點

資料庫日志——binlog、redo log、undo log掃盲binlogredo logUndo log

日志是資料庫中比較重要的組成部分,很多核心的功能必須依靠日志才能完成。

該篇文章簡要介紹了binlog、redo log與undo log,能夠在一定程度上拓寬對mysql日志的整體認識。

binlog

又稱歸檔日志,由Server層實作與記錄,是以對任何引擎都有效。

binlog是一種隻記錄對表中資料以及對表結構産生更改操作的二進制檔案,比如有insert、update、delete、create table、alter table等操作,不記錄select、show,因為這些操作不會産生任何更改。不過就算一個update未産生資料變化,也是會被記錄進去的。

你可以了解binlog是直接記錄sql語句,或者說記錄原始sql邏輯,是以binlog屬于邏輯日志。

binlog是追加寫入的,一個檔案寫滿,會重新建立一個檔案繼續寫,檔案名稱是mysql-bin.xxxxxx,例如myql-bin.000001,序号部分會遞增。

binlog的格式

binlog有三種格式,可以通過binlog-format來設定

STATEMENT

直接記錄操作的sql語句,例如update student set name='tom' where id=1;

優點:

這種格式的binlog,可以直接進行閱讀。

不記錄具體的行資料,日志量不會很大,性能較優。

缺點:

當binlog用于主從之間的複制時,如果目前的sql語句為随機函數rand()、目前日期now()等,在重制之後具有不同的值,具有歧義性,可能會造成複制後資料不一緻。

ROW

對于update student set name='tom' where id=1操作,會記錄id=1這條資料中name字段在修改前與修改後的資料。

優點:

準确性強

缺點:

可讀性差,需要借助mysqlbinlog解析。

如果經常修改一些字段比較長的資料,會造成生成的binlog日志量變多,性能稍弱。

當然,alter table等直接改變表結構的語句,也會快速增加日志量與磁盤IO。

MIXED

其實就是一種對STATEMENT與ROW的混合使用方式

對不會造成歧義的操作使用STATEMENT格式進行記錄,否則使用ROW格式記錄。

對表結構的修改操作,也使用ROW格式進行記錄。

不過,比較推薦的是ROW格式,特别是在SSD、雲端存儲、大帶寬普及的今天,這點兒的存儲空間與磁盤IO還是吃得消的,滴滴基于Binlog的采集架構就是直接使用的ROW格式。

binlog的使用場景

主從複制

當我們使用主從結構的mysql時,從庫需要同步主庫的資料。

這個時候主庫會将自己的binlog異步發送給從庫,從庫在本地完成sql回放,來達到主從資料一緻的目的。

主從複制之間可能會存在延遲,當主庫隻負責寫,從庫隻負責讀時,寫完主庫之後的立馬讀從庫,可能會出現問題。

關于主從複制原理及主從延遲的解決方案,會另開篇幅。

資料庫日志——binlog、redo log、undo log掃盲binlogredo logUndo log

資料恢複

當誤删生産資料時,可以通過binlog來恢複。

找到生産庫最近的一次全量備份,首先由全量備份恢複到臨時庫中。

接着從全量備份的時間點開始,重放binlog一直到mysql不産生新的binlog為止,另外要注意删除binlog中誤操作的語句,最後切換臨時庫為生産庫。

值得注意的一點是,binlog預設是不開啟的。

redo log

又稱重做日志,是Innodb引擎中特有的日志。如果目前使用的引擎是Myisam或者Memory,那就無從談起redo log。

和binlog的内容不同,redo log記錄了“在某個資料頁上做了哪些修改”,屬于實體日志。

為什麼要有redo log?

Innodb引擎是以頁為機關來和磁盤互動的,一般來說,如果一個事務送出後,需要将修改後的資料頁寫回到磁盤中。

如果本次事務隻修改目前資料頁中的幾個Byte,直接将目前資料頁的所有内容刷到磁盤後,涉及到大量的随機寫,IO成本很高,性能比較低。

如果事務送出後,先将“對哪個資料頁做了哪些修改”順序寫入redo log,之後會在合适的時機寫回到buffer pool(你可以把buffer pool了解為緩沖池,如果查詢到一條記錄時,會将記錄所在的資料頁加載進緩沖池中。之後再進行查找時,先查詢緩沖池,查不到再查磁盤,查到了就再放入到緩沖池中。這樣做,在一定程度上可以減少IO成本,提升性能)中,最後将buffer pool中的資料頁刷盤,在一定程度上可以減少IO成本。

此外,binlog是不支援crash-safe,即崩潰恢複的,隻是支援誤删資料恢複。當redo log與binlog結合在一起的時候,光芒就出現了,此處應該有迪迦。redo log中較實際資料頁中多出來的那部分日志,就是崩潰後用于恢複的日志。

redo log的記錄方式

和binlog追加寫不同,redo log采用的是循環寫。之是以用循環寫,是因為之前恢複的資料再儲存在redo log中就沒有任何意義了。

假設redo log最終會寫入到4個檔案中,每個檔案的大小都是1GB,則此時能夠記錄的最大日志量為4GB。

比如先從1号檔案中寫入,寫滿之後,就換到2号檔案中。4個檔案全部寫滿後,再回到1号檔案從頭繼續寫。

資料庫日志——binlog、redo log、undo log掃盲binlogredo logUndo log

 這裡還有兩個指針,write position與check point

write position

指向redo log的記錄進度,write position指針走過的區域,代表着redo log的日志量逐漸增長。

check point

指向資料頁刷盤後的恢複進度,check point指針走過的區域,會将區域内redo log資料用于恢複,接着将redo log擦除。

資料庫日志——binlog、redo log、undo log掃盲binlogredo logUndo log

 兩個指針的運動方向,都是順時針方向。

是以,從write position順時針到check point之間的區域,都是空着的部分。

當redo log記錄過快時,write position可能會追趕上check point。此時就需要停止redo log記錄,并将所有檔案中的redo log恢複。

在這裡,有必要總結一下binlog與redo log的差別。

binlog與redo log的差別

binlog redo log
日志歸屬 由Server層實作,所有的引擎都可以使用 由Server層實作,所有的引擎都可以使用
日志類型 邏輯日志,記錄原始的sql邏輯或資料變更的前後内容 實體日志,記錄在哪個資料頁上進行了哪些更改
寫入方式 追加寫,寫滿則建立一個新檔案繼續寫 循環寫,全部寫滿就從頭開始
适用場景 主從同步與誤删恢複 崩潰恢複

在一條類型為update的sql語句的執行背後,涉及到binglog與redo log的兩階段送出,這個也會另開篇幅。

Undo log

undo log主要用于事務復原時恢複原來的資料

mysql在執行sql語句時,會将一條邏輯相反的日志儲存到undo log中。是以,undo log中記錄的也是邏輯日志。

當sql語句為insert時,會在undo log中記錄本次插入的主鍵id。等事務復原時,delete此id即可。

當sql語句為update時,會在undo log中記錄修改前的資料。等事務復原時,再執行一次update,得到原來的資料。

當sql語句為delete時,會在undo log中記錄删除前的資料。等事務復原時,insert原來的資料即可。

資料庫事務四大特性中的原子性,即事務具有不可分割性,要麼全部成功,要麼全部失敗,其底層就靠undo log實作。在某一步執行失敗時,會對之前事務的語句進行復原。

另外,undo log與ReadView合作可以實作多版本并發控制MVCC(Mutil-Version Concurrency Control)。

MVCC

對于MVCC,簡單來講,就是mysql儲存了一行資料在多個時間點的快照,是一種使用空間換取時間的政策,能做到讀(快照讀,可以了解就是普通的select語句)寫不加鎖。

你可以暫時了解為,每一份快照包含了一行undo log日志,各個版本的快照通過指針連接配接起來,這樣可以順着指針快速找到上一份快照。

資料庫日志——binlog、redo log、undo log掃盲binlogredo logUndo log

(圖檔來源于網際網路,聯系侵删) 

關于MVCC實作原理,也會另開篇幅。

繼續閱讀