關(guān)于MySQL日志,我與阿里P9都聊了些啥?
作者個(gè)人研發(fā)的在高并發(fā)場(chǎng)景下,提供的簡單、穩(wěn)定、可擴(kuò)展的延遲消息隊(duì)列框架,具有精準(zhǔn)的定時(shí)任務(wù)和延遲隊(duì)列處理功能。自開源半年多以來,已成功為十幾家中小型企業(yè)提供了精準(zhǔn)定時(shí)調(diào)度方案,經(jīng)受住了生產(chǎn)環(huán)境的考驗(yàn)。為使更多童鞋受益,現(xiàn)給出開源框架地址:https://github.com/sunshinelyz/mykit-delay
寫在前面
周末,我與阿里P9資深技術(shù)專家(這里就不說名字了),聊起了MySQL這個(gè)話題,為啥會(huì)聊這個(gè)呢?因?yàn)樗吹轿页霭媪艘徊俊禡ySQL技術(shù)大全:開發(fā)、優(yōu)化與運(yùn)維實(shí)戰(zhàn)》,對(duì)書籍的評(píng)價(jià)也是不錯(cuò)的。隨后,我們聊了關(guān)于MySQL的幾個(gè)話題,其中一個(gè)就是MySQL的日志機(jī)制。今天,我就把大概聊的一些內(nèi)容以書面文章的形式分享給大家。希望能夠?yàn)樾』锇閭儙韺?shí)質(zhì)性的幫助!
文章已收錄到:
https://github.com/sunshinelyz/technology-binghe
https://gitee.com/binghe001/technology-binghe
MySQL日志
說起MySQL的日志,有三種類型的日志對(duì)于MySQL來說是至關(guān)重要的,這三種日志分別為:Binlog、Undo Log 和 Redo Log。
由于Binlog和UndoLog有類似的地方,所以,我們按照如下順序依次介紹MySQL中的三大日志原理:Undo Log——> Redo Log ——> Binlog。
Undo Log日志
什么是Undo Log
顧名思義,Undo Log的字面意思就是撤銷操作的日志,指的是使MySQL中的數(shù)據(jù)回到某個(gè)狀態(tài)。
在MySQL數(shù)據(jù)庫中,事務(wù)開始之前,MySQL會(huì)將待修改的記錄保存到Undo Log中,如果數(shù)據(jù)庫崩潰或者事務(wù)需要回滾時(shí),MySQL可以通過利用Undo Log日志,將數(shù)據(jù)庫中的數(shù)據(jù)回滾到之前的狀態(tài)。
MySQL新增、修改和刪除數(shù)據(jù)時(shí),在事務(wù)開始前,就會(huì)將信息寫入U(xiǎn)ndo Log中。事務(wù)提交時(shí),并不會(huì)立刻刪除Undo Log, InnoDB存儲(chǔ)引擎會(huì)將事務(wù)對(duì)應(yīng)的Undo Log放入待刪除列表中,之后會(huì)通過后臺(tái)的purge thread對(duì)待刪除的列表進(jìn)行刪除處理。這里,值得注意的是:Undo Log是一種 邏輯日志, 記錄的是一個(gè)變化過程。比如,MySQL執(zhí)行一個(gè)delete操作,Undo Log就會(huì)記錄一個(gè)insert操作;MySQL執(zhí)行一個(gè)insert操作,Undo Log就會(huì)記錄一個(gè)delete操作;MySQL執(zhí)行一個(gè)update操作,Undo Log就會(huì)記錄一個(gè)相反的update操作。
Undo Log以段的方式來管理和記錄日志信息,在InnoDB存儲(chǔ)引擎的數(shù)據(jù)文件中,包含了一種叫做rollback segment的回滾段,其內(nèi)部包含了1024個(gè)undo log senment。
Undo Log作用
Undo Log對(duì)于MySQL實(shí)現(xiàn)事務(wù)來說,起著至關(guān)重要的作用,它實(shí)現(xiàn)了事務(wù)的原子性和多版本并發(fā)控制,也就是我們經(jīng)常說的MVCC。
- 實(shí)現(xiàn)事務(wù)的原子性
Undo Log能夠?qū)崿F(xiàn)MySQL事務(wù)的原子性,在事務(wù)的處理過程中,如果MySQL出現(xiàn)了錯(cuò)誤或者用戶手動(dòng)執(zhí)行了事務(wù)的回滾操作(執(zhí)行了rollback操作),MySQL可以利用Undo Log日志將數(shù)據(jù)庫中的數(shù)據(jù)恢復(fù)到之前的狀態(tài)。
- 實(shí)現(xiàn)MVCC機(jī)制
Undo Log在MySQL的InnoDB存儲(chǔ)引擎中實(shí)現(xiàn)了多版本并發(fā)控制(MVCC)機(jī)制。事務(wù)未提交前,Undo Log保存了未提交之前的版本數(shù)據(jù),Undo Log中的數(shù)據(jù)可以作為舊版本數(shù)據(jù)的副本或者快照以便其他并發(fā)事務(wù)進(jìn)行讀取操作。
事務(wù)A手動(dòng)開啟事務(wù)后,對(duì)goods數(shù)據(jù)表中id為1的數(shù)據(jù)進(jìn)行更新操作,首先會(huì)把更新命中的數(shù)據(jù)寫入到Undo Buffer中。在事務(wù)A未提交之前,此時(shí),事務(wù)B手動(dòng)開啟事務(wù),對(duì)goods數(shù)據(jù)表中的id為1的數(shù)據(jù)進(jìn)行查詢操作,此時(shí)的事務(wù)B會(huì)讀取Undo Log中的數(shù)據(jù)并返回給客戶端,這就是MySQL中的MVCC機(jī)制。
可以在MySQL中通過下面的命令來查看控制Undo Log日志的參數(shù)。
- show variables like '%innodb_undo%';
Redo Log日志
說了MySQL中的Undo Log,我們?cè)賮砜纯碝ySQL中的Redo Log日志。
什么是Redo Log
顧名思義Redo Log的字面意思就是重做日志,指的是在數(shù)據(jù)庫出現(xiàn)意外情況時(shí)能夠?qū)χ匦聢?zhí)行某種操作。在MySQL中,事務(wù)中修改的任何數(shù)據(jù),都會(huì)將最新的數(shù)據(jù)寫入Redo Log中進(jìn)行備份。
在MySQL中,隨著事務(wù)操作的執(zhí)行,就會(huì)產(chǎn)生Redo Log日志,在事務(wù)提交時(shí)會(huì)產(chǎn)生Redo Log并將其寫入Redo Buffer,Redo Buffer也并不是隨著事務(wù)的提交就會(huì)被立刻寫入到磁盤中,而是等事務(wù)操作的臟頁寫入到磁盤之后,Redo Log的使命也就完成了,此時(shí),Redo Log日志占用的空間可以重新利用,會(huì)被后續(xù)產(chǎn)生的Redo Log日志覆蓋。
Redo Log的原理
Redo Log 能夠?qū)崿F(xiàn)事務(wù)的持久性,防止在發(fā)生故障的時(shí)間點(diǎn),有臟頁未寫入表的 ibd 文件中,在重啟 MySQL 服務(wù)的時(shí)候,根據(jù) Redo Log 進(jìn)行重做,從而將未提交的事務(wù)進(jìn)行持久化。這個(gè)過程可以簡化為下圖所示。
Redo Log的寫機(jī)制
Redo Log文件的內(nèi)容是以順序循環(huán)的方式寫入文件的,寫滿時(shí)就會(huì)回到第一個(gè)文件,進(jìn)行覆蓋寫。
- Write Pos 是當(dāng)前記錄的位置,一邊寫一邊后移,寫到最后一個(gè)文件末尾后就回到 0 號(hào)文件開頭;
- CheckPoint是當(dāng)前要擦除的位置,也是往后推移并且循環(huán)的,擦除記錄前要把記錄更新到數(shù) 據(jù)文件;
Write Pos 和 CheckPoint之間還空著的部分,可以用來記錄新的操作。如果 Write Pos 追上 CheckPoint,表示已經(jīng)寫滿,此時(shí)就需要向后移動(dòng)CheckPoint來擦除數(shù)據(jù)。
每個(gè)InnoDB存儲(chǔ)引擎至少有1個(gè)重做日志文件組(group),每個(gè)文件組至少有2個(gè)重做日志文件,默認(rèn)為ib_logfile0和ib_logfile1 。
可以在MySQL中通過如下命令來查看控制Redo Log的參數(shù)。
- show variables like '%innodb_log%';
Redo Log寫入機(jī)制
在Redo Log日志信息從Redo Buffer持久化到Redo Log時(shí),具體的持久化策略可以通過innodb_flush_log_at_trx_commit 參數(shù)進(jìn)行設(shè)置,具體策略如下所示。
- 0:每秒提交 Redo buffer ->OS cache -> flush cache to disk,可能丟失一秒內(nèi)的事務(wù)數(shù)據(jù)。由后臺(tái)Master線程每隔 1秒執(zhí)行一次操作。
- 1(默認(rèn)值):每次事務(wù)提交執(zhí)行 Redo Buffer -> OS cache -> flush cache to disk,這種方式最安全,性能最差。
- 2:每次事務(wù)提交執(zhí)行 Redo Buffer -> OS cache,然后由后臺(tái)Master線程再每隔1秒執(zhí)行OS cache -> flush cache to disk 的操作。
一般建議選擇取值2,因?yàn)?MySQL 掛了數(shù)據(jù)沒有損失,整個(gè)服務(wù)器掛了才會(huì)損失1秒的事務(wù)提交數(shù)據(jù)。
Binlog日志
什么是Binlog
Binlog記錄所有MySQL數(shù)據(jù)庫表結(jié)構(gòu)變更以及表數(shù)據(jù)修改的二進(jìn)制日志,不會(huì)記錄select和show這類查詢操作的日志。Binlog日志是以事件形式記錄,還包含語句所執(zhí)行的消耗時(shí)間。開啟Binlog日志有以下兩個(gè)最重要的使用場(chǎng)景。
- 主從復(fù)制:在主庫中開啟Binlog功能,這樣主庫就可以把Binlog傳遞給從庫,從庫拿到Binlog后實(shí)現(xiàn)數(shù)據(jù)恢復(fù)達(dá)到主從數(shù)據(jù)一致性。
- 數(shù)據(jù)恢復(fù):通過mysqlbinlog等工具來恢復(fù)數(shù)據(jù)
Binlog文件記錄模式
Binlog文件記錄模式有STATEMENT、ROW和MIXED三種,具體含義如下。
ROW模式
ROW(row-based replication, RBR):日志中會(huì)記錄每一行數(shù)據(jù)被修改的情況,然后在slave端對(duì)相同的數(shù)據(jù)進(jìn)行修改。
優(yōu)點(diǎn):能清楚記錄每一個(gè)行數(shù)據(jù)的修改細(xì)節(jié),能完全實(shí)現(xiàn)主從數(shù)據(jù)同步和數(shù)據(jù)的恢復(fù)。
缺點(diǎn):批量操作,會(huì)產(chǎn)生大量的日志,尤其是alter table會(huì)讓日志暴漲。
STATMENT模式
STATMENT(statement-based replication, SBR):每一條被修改數(shù)據(jù)的SQL都會(huì)記錄到master的Binlog中,slave在復(fù)制的時(shí)候SQL進(jìn)程會(huì)解析成和原來master端執(zhí)行過的相同的SQL再次執(zhí)行。簡稱SQL語句復(fù)制。
優(yōu)點(diǎn):日志量小,減少磁盤IO,提升存儲(chǔ)和恢復(fù)速度
缺點(diǎn):在某些情況下會(huì)導(dǎo)致主從數(shù)據(jù)不一致,比如last_insert_id()、now()等函數(shù)。
MIXED模式
MIXED(mixed-based replication, MBR):以上兩種模式的混合使用,一般會(huì)使用STATEMENT模式保存binlog,對(duì)于STATEMENT模式無法復(fù)制的操作使用ROW模式保存binlog,MySQL會(huì)根據(jù)執(zhí)行的SQL語句選擇寫入模式 。
Binlog文件結(jié)構(gòu)
對(duì)于MySQL的Binlog文件結(jié)構(gòu)有三種版本,見下圖。
關(guān)于Binlog文件結(jié)構(gòu)的具體信息,小伙伴們可以參考MySQL的官方文檔,具體鏈接為:https://dev.mysql.com/doc/internals/en/event-header-fields.html
Binlog寫機(jī)制
根據(jù)記錄模式和操作觸發(fā)event事件生成log event(事件觸發(fā)執(zhí)行機(jī)制)。
將事務(wù)執(zhí)行過程中產(chǎn)生的日志時(shí)間(log event)寫入緩沖區(qū),每個(gè)事務(wù)線程都有一個(gè)緩沖區(qū)。Log Event保存在一個(gè)binlog_cache_mngr數(shù)據(jù)結(jié)構(gòu)中,在該結(jié)構(gòu)中有兩個(gè)緩沖區(qū),一個(gè)是stmt_cache,用于存放不支持事務(wù)的信息;另一個(gè)是trx_cache,用于存放支持事務(wù)的信息。
事務(wù)在提交階段會(huì)將產(chǎn)生的log event寫入到外部binlog文件中。不同事務(wù)以串行方式將log event寫入Binlog文件中,所以一個(gè)事務(wù)包含的log event信息在binlog文件中是連續(xù)的,中間不會(huì)插入其他事務(wù)的log event。
Binlog文件操作
Binlog狀態(tài)查看
- show variables like 'log_bin';
開啟Binlog功能,需要修改my.cnf或my.ini配置文件,在[mysqld]下面增加log_bin=mysql_bin_log,重啟 MySQL服務(wù)。
- binlog-format=ROW
- log-bin=mysqlbinlog
使用show binlog events命令
- show binary logs; //等價(jià)于show master logs;
- show master status;
- show binlog events;
- show binlog events in 'mysqlbinlog.000001';
使用mysqlbinlog 命令
- mysqlbinlog "文件名"
- mysqlbinlog "文件名" > "test.sql"
使用 binlog 恢復(fù)數(shù)據(jù)
- //按指定時(shí)間恢復(fù)
- mysqlbinlog --start-datetime="2021-02-28 18:00:00" --stopdatetime="2021-03-01 00:00:00" mysqlbinlog.000001 | mysql -uroot -p123456
- //按事件位置號(hào)恢復(fù)
- mysqlbinlog --start-position=1789 --stop-position=2674 mysqlbinlog.000001
- | mysql -uroot -p123456
刪除Binlog文件
- purge binary logs to 'mysqlbinlog.000001'; //刪除指定文件
- purge binary logs before '2021-03-01 00:00:00'; //刪除指定時(shí)間之前的文件
- reset master; //清除所有文件
可以通過設(shè)置expire_logs_days參數(shù)來啟動(dòng)自動(dòng)清理功能。默認(rèn)值為0表示沒啟用。設(shè)置為大于0的整數(shù)表示超出多少天binlog文件會(huì)自動(dòng)清除。
本文轉(zhuǎn)載自微信公眾號(hào)「冰河技術(shù)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系冰河技術(shù)公眾號(hào)。