Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
日志是數據庫中比較重要的組成部分,很多核心的功能必須依靠日志才能完成。
該篇文章簡要介紹了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來設定
直接記錄操作的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字段在修改前與修改后的數據。
優點:
準確性強
缺點:
可讀性差,需要借助解析。
如果經常修改一些字段比較長的數據,會造成生成的binlog日志量變多,性能稍弱。
當然,alter table等直接改變表結構的語句,也會快速增加日志量與磁盤IO。
MIXED
其實就是一種對與ROW的混合使用方式
對不會造成歧義的操作使用格式進行記錄,否則使用ROW格式記錄。
對表結構的修改操作,也使用ROW格式進行記錄。
不過,比較推薦的是ROW格式,特別是在SSD、云端存儲、大帶寬普及的今天,這點兒的存儲空間與磁盤IO還是吃得消的,滴滴基于Binlog的采集架構就是直接使用的ROW格式。
binlog的使用場景 主從復制
當我們使用主從結構的mysql時,從庫需要同步主庫的數據。
這個時候主庫會將自己的binlog異步發送給從庫,從庫在本地完成sql回放,來達到主從數據一致的目的。
主從復制之間可能會存在延遲,當主庫只負責寫,從庫只負責讀時,寫完主庫之后的立馬讀從庫,可能會出現問題。
關于主從復制原理及主從延遲的解決方案,會另開篇幅。
數據恢復
當誤刪生產數據時,可以通過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號文件從頭繼續寫。
這里還有兩個指針,write 與check point
write
指向redo log的記錄進度,write 指針走過的區域,代表著redo log的日志量逐漸增長。
check point
指向數據頁刷盤后的恢復進度,check point指針走過的區域,會將區域內redo log數據用于恢復,接著將redo log擦除。
兩個指針的運動方向,都是順時針方向。
因此,從write 順時針到check point之間的區域,都是空著的部分。
當redo log記錄過快時,write 可能會追趕上check point。此時就需要停止redo log記錄,并將所有文件中的redo log恢復。
在這里,有必要總結一下binlog與redo log的區別。
binlog與redo log的區別 log
日志歸屬
由Server層實現,所有的引擎都可以使用
Innodb引擎中特有的日志
日志類型
邏輯日志,記錄原始的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與合作可以實現多版本并發控制MVCC(Mutil-Version Control)。
MVCC
對于MVCC,簡單來講,就是mysql保存了一行數據在多個時間點的快照,是一種使用空間換取時間的策略,能做到讀(快照讀,可以理解就是普通的select語句)寫不加鎖。
你可以暫時理解為,每一份快照包含了一行undo log日志,各個版本的快照通過指針連接起來,這樣可以順著指針快速找到上一份快照。
(圖片來源于互聯網,聯系侵刪)
關于MVCC實現原理,也會另開篇幅。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。