您好,登錄后才能下訂單哦!
這篇文章主要介紹“什么是Redo log與Binlog”,在日常操作中,相信很多人在什么是Redo log與Binlog問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”什么是Redo log與Binlog”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
MySQL是常用的數據庫存儲應用,我們利用它存儲信息、查詢信息、處理事務。特別是為了提高可用性會用到事務一致性、主從復制、數據恢復等功能。我們在使用這些功能的時候,是否想過其背后有哪些原理和機制在支撐?今天我們聚焦redo log和binlog兩個MySQL的日志機制,以及它們是如何配合提高MySQL存儲可靠性的。今天會學到以下內容:
Redo log
Redo log 解決了什么問題?
Redo log的執行流程
Redo log的寫入方式
Redo log記錄形式
Binlog
a.Binlog解決了什么問題?
b.Binlog的日志格式
Redo log 與Binlog的區別與合作
Redo log
1.Redo log 解決了什么問題?
MySQL應用中處理事務是一個重要的任務,而在事務處理的四個特性中(ACID),存在一個持久性(Durability),它表示在事務執行過程中,對數據的所有改動都必須在事務成功結束前保存至某種物理存儲設備中。
換句話說,只要事務提交成功,那么對數據庫做的修改就被永久保存下來了,不可能因為任何原因再回到原來的狀態。那么為什么要在MySQL中考慮事務持久性的問題呢?假設這么一種場景,當數據存儲的事務正在執行但是數據還沒有保存的時候,數據庫宕機了,那么這些沒來得及存儲到磁盤的數據就丟失了,如果此時有一種機制能夠記錄這個事務的操作,當數據庫服務恢復的時候,運行記錄的操作那么這些沒有來得及存儲的數據就能夠正確保存了。
Redo log 就是通過這種手段來實現事務持久性的。上面的場景中是數據庫服務器宕機,如果發生其他故障導致尚有臟頁未寫入磁盤的場景,也是可以通過Redo log恢復的。
1.Redo log的執行流程
了解了為什么使用redo log 以后再來看看其執行流程,如圖1 所示:
圖1 redo log執行流程
該泳道圖由MySQL客戶端、MySQL Server 層和MySQL 存儲引擎層組成,由于redo log是在Innodb存儲引擎中使用的,這里假設存儲引擎就是Innodb。由于MySQL Server 層主要負責SQL語句的分析、優化和執行工作,而MySQL存儲引擎層主要負責存儲工作,redo log 也運行在這一層。
跟隨圖中的序號來看看redo log 的運行流程。
1. 從MySQL客戶端請求語句“update T set a=1 where id=2”,并發現MySQL Server 層。
2. 接收到SQL請求以后MySQL Server 層會對其進行分析、優化、執行等處理工作,將生成的SQL執行計劃發到存儲引擎層執行。
3. 存儲引擎層將“a修改為1”的這個操作記錄到內存中。
4. 記錄到內存以后會修改redo log 的記錄,會在添加一行記錄,其內容是“需要在哪個數據頁上做什么修改”。
5. 此后,將事務的狀態設置為prepare ,說明已經準備好提交事務了。
6. 等到MySQL Server 層處理完事務以后,會將事務的狀態設置為commit,也就是提交該事務。
7. 在收到事務提交的請求以后,redo log 會把剛才寫入內存中的操作記錄寫入到磁盤中,從而完成整個日志的記錄過程。
2Redo log的寫入方式
從上面介紹的Redo log 的執行流程中不難看出,redo log在寫入磁盤之前會先將內容寫到內存中。因此,redo log的寫入包括兩部分內容:一部分是內存中的日志緩沖,稱作redo log buffer;另一部分是磁盤日志文件,稱作 redo log file。MySQL每執行一條DML語句,先將更新記錄寫入redo log buffer ,然后再寫入redo log file。我們將這種先寫日志,再寫磁盤的方式稱為 WAL(Write-Ahead Logging)技術。
如圖2所示:
圖2 redo log 寫入方式
順著箭頭的方向從左往右看,日志最開始會寫入位于存儲引擎Innodb的redo log buffer中,這個也就是所謂的用戶空間(user space),然后再將日志保存到操作系統內核空間(kernel space)的緩沖區(OS buffer)中。
最后,再從OS buffer寫入到磁盤上的redo log file中,完成寫入操作,這個寫入磁盤的操作也稱作“刷盤”。
了解了redo log的寫入方式之后,我們發現主要完成的操作是redo log buffer 到磁盤的redo log file的寫入過程,其中需要經過OS buffer進行中轉。關于redo log buffer寫入redo log file的時機,可以通過 參數innodb_flush_log_at_trx_commit 進行配置,各參數值含義如下:
參數為0的時候,稱為“延遲寫”。事務提交時不會將redo log buffer中日志寫入到OS buffer,而是每秒寫入OS buffer并調用寫入到redo log file中。換句話說,這種方式每秒會發起寫入磁盤的操作,假設系統崩潰,只會丟失1秒鐘的數據。
參數為1 的時候,稱為“實時寫,實時刷”。事務每次提交都會將redo log buffer中的日志寫入OS buffer并保存到redo log file中。其有點是,即使系統崩潰也不會丟失任何數據,缺點也很明顯就是每次事務提交都要進行磁盤操作,性能較差。
參數為2的時候,稱為“實時寫,延遲刷”。每次事務提交寫入到OS buffer,然后是每秒將日志寫入到redo log file。這樣性能會好點,缺點是在系統崩潰的時候會丟失1秒中的事務數據。
3.Redo log記錄形式
redo log是通過循環寫入的方式保存的。
如圖3所示:
圖3 redo log 循環寫入(素材來源于互聯網)
redo log buffer(內存中)是由首尾相連的四個文件組成的,它們分別是:ib_logfile_1、ib_logfile_2、ib_logfile_3、ib_logfile_4。
寫入的方式也是從文件的頭部開始寫入(假設),每增加一條日志記錄就往文件的尾部添加,直到把四個文件寫滿,再回到文件開頭的地方(ib_logfile_1)繼續寫,繼續寫的時候會覆蓋之前的記錄。
圖3中write pos表示當前寫入記錄位置(寫入磁盤的數據頁的邏輯序列位置),check point表示刷盤(寫入磁盤)后對應的位置。write pos到check point之間的部分用來記錄新日志,也就是留給新記錄的空間。check point到write pos之間是待刷盤的記錄,如果不刷盤會被新記錄覆蓋。
當write pos指針追上check point的時候(也就是新記錄即將覆蓋老記錄的時刻),會推動check point向前移動,也就是催促其將記錄刷到磁盤中,這樣好空出位置給新記錄。
當redo log buffer根據check pint刷盤以后,針對Innodb引擎而言是以頁為單位進行磁盤存儲,一個事務可能一個或者多個數據頁,每個頁面修改多個字節。當重新啟動Innodb存儲引擎的時候,是會進行恢復操作。因為redo log記錄的是數據頁的物理變化,恢復的速度比邏輯日志(binlog)要快。
在重啟Innodb時,首先會檢查磁盤中數據頁的邏輯序列位置,如果數據頁的邏輯序列位置小于日志中的位置,則會從check point開始恢復。如果宕機的時候,正處于check point的刷盤過程中,且數據頁的刷盤進度超過了日志頁的刷盤進度,此時會出現數據頁中記錄的邏輯序列位置大于日志中的邏輯序列位置,這時超出日志進度的部分將不會重做,因為這本身就表示已經做過的事情,無需再重做。
Binlog
4.Binlog 解決了什么問題?
對于MySQL數據庫而言增加數據的可靠性是一個永恒的話題,其中主從復制和數據恢復就是增強數據可靠性的兩個重要功能。Binlog就是為實現這兩個功能而設置的。
主從復制的場景中在Master 端會開啟binlog ,然后將 binlog 發送到各個Slave 端,Slave 端重放binlog 從而達到Slave 端的數據和Master端的數據保持一致。在數據恢復場景,通過使用mysqlbinlog 工具以及對應的binlog 將數據恢復到指定的時間點。那么可以把binlog 解決的問題總結為兩點,就是主從復制和數據恢復。
5.Binlog的日志格式
從記錄方式上來看binlog通過追加的方式記錄,當日志文件尺寸大于給定值后,后續的日志會記錄到新的文件上。這個與 redo log 的循環記錄產生鮮明的對比,同時binlog 可通過配置參數 max_binlog_size 設置每個binlog 文件的大小。
從日志格式來看,Binlog 日志有三種格式,分別為 STATMENT 、 ROW 和 MIXED 。
在 MySQL 5.7.7 之前,默認的格式是 STATEMENT , MySQL 5.7.7 之后,默認值是 ROW 。日志格式通過 binlog-format 指定。三種格式的定義和優缺點如下:
lSTATEMENT:基于SQL語句的復制(statement-based replication, SBR),記錄的是修改的SQL語句。
n 優點:由于不用記錄每行日志的更改,因此日志文件小,減少了日志量,節約了IO,提高了性能;
n 缺點:準確性差,對一些系統行數不能準確復制,例如:now()、uuid()。
lROW:基于行的復制(row-based replication, RBR),不記錄每條SQL語句的上下文信息,只記錄每行實際數據的變更 。
n 優點: 準確性強,能夠準確復制數據的變更。
n 缺點: 產生的日志文件較大,從造成較大的網絡IO和磁盤IO。尤其是alter table的時候會讓日志暴漲。
lMIXED:基于STATMENT和ROW兩種模式的混合復制( mixed-based replication, MBR ),默認使用STATEMENT模式保存,STATEMENT模式無法復制的操作使用ROW模式。
n 優點:準確性強、文件大小適中。
n 缺點:有可能發生主從不一致的現象。
在MySQL中可以通過“show binlog events” 命令查看binlog日志的事件。如代碼段1 所示,這里通過上述命令查看“mysql-bin.000002”文件中的binlog 日志情況。
mysql> show binlog events in 'mysql-bin.000002';
代碼段1
如圖4所示:
圖4 顯示binlog 日志內容
通過上述命令展示對應binlog 日志事件,從左到右展示如下:
Log_name:描述存放binlog日志的文件名字。
Pos:描述記日志的開始位置。
Event_type:描述時間類型,例如:查詢、插入等。
Server_id:對應數據庫服務器的ID。
End_log_pos:日志結束的位置。
Info:執行的SQL語句。
上面是查看日志的事件,這里也可以通過mysqlbinlog命令可以查看binlog的內容。如代碼段2 所示,通過mysqlbinlog 命令查看mysql-bin.000002的內容。
mysql> mysqlbinlog 'mysql-bin.000002';
代碼段2
如圖5所示:
圖5 binlog 日志的內容
我們將上述查看命令返回的結果截取其中一部分給大家講解,我們從上往下看:
“at 294”說明“事件”的起點,也就是從文件的第294字節開始。
“120330 17:54:46”表示事件發生的時間戳信息。
“end_log_pos 388 ”表示日志記錄結束的字節位置,也就是在文件的第388 字節截止。
"exec_time=28",表示事件執行花費的時間。
“error_code=0”,表示錯誤代碼為0,也就是沒有錯誤。
“server id 1”,表示服務器的標識id。
需要注意的是binlog的事務提交,是一次性將事務進行提交(一個事物包含一個或者多個SQL語句)。而redo log可以在事務開始之后就開始逐步寫入磁盤。因此對于事務的提交,即便是較大的事務,提交(commit)都是很快的,但是在開啟了binlog的情況下,對于較大事務的提交,可能會變得比較慢。因為binlog事務提交是一次性寫入。
6.Redo log與Binlog區別與合作
前面介紹了redo log 和 binlog,那么這里總結一下它們之間的區別如下表格。
由 binlog 和 redo log 的區別可知:binlog 日志只用于歸檔,但僅僅依靠 binlog 是沒有 crash-safe 能力的。但只有 redo log 也不行,因為 redo log 是 InnoDB 特有的,且日志記錄落盤后會被覆蓋掉。因此需要 binlog 和 redo log 二者同時記錄,才能保證當數據庫發生宕機重啟時,數據不會丟失。
那么如何讓兩個日志保持一致呢?
如圖5所示:
圖5 redo log 和 binlog 事務保持一致
該圖沿用了圖1 的例子,稍微不同的是加入了一個步驟。看到綠色虛線框的部分加入了寫入binlog的步驟。當事務為prepare狀態的時候,在commit事務之間,會先將日志保存到binlog當中,然后再提交給 Innodb中的redo log,最后完成commit的操作。
再聚焦于redo log 和 binlog 在提交成功和失敗兩種情況中的狀態變化。
如圖6 所示:
圖6 redo log 和 binlog 狀態變遷圖(素材來源于互聯網)
從上往下看,先看紅色線條的部分,當寫入redo log并且事務狀態為prepare的時候,如果寫入成功直接寫入binlog,如果binlog 寫入也成功,redo log 狀態設置為commit。如果寫入binlog的時候失敗了,沿著紅色箭頭向上回滾此次事務。再回到最上面,看綠色箭頭的部分,如果寫入redo log 狀態為prepare 此時寫入失敗,不再寫入binlog,事務直接回滾。
可以看出這里為了保持兩個日志的一致性,使用了兩段提交。redo log和binlog是兩個獨立的邏輯,如果不用兩階段提交,要么就是先寫完redo log再寫 binlog,或者先寫binlog再寫 redo log。看看這兩種方式會有什么問題:
先寫redo log后寫binlog。假設在redo log寫完,binlog還沒有寫完的時候,也就是說binlog 沒有事務中更新的語句。此時MySQL重啟并使用binlog來恢復數據,由于之前更新的語句沒有保存數據庫就會少了一次更新,導致數據的不一致。
先寫binlog后寫redo log。如果在binlog寫完之后服務器宕機了,由于redo log還沒寫,也就是數據還沒有寫到數據庫中。但是binlog里面已經記錄了,意思是把本來不應該更新的數據記錄到更新里面了。此時MySQL數據庫重啟,就會把這條不該更新的數據更新到數據庫中,導致數據的不一致。
到此,關于“什么是Redo log與Binlog”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。