MySQL日誌系統

2022-06-10 17:15:11 字數 2812 閱讀 1261

從乙個更新操作開始

mysql> create table t(id int primary key, c int);

mysql> update t set c=c+1 where id=2;
與查詢流程不一樣的是,更新流程還涉及兩個重要的日誌模組,它們正是我們今天要討論的主角:redo log(重做日誌)和 binlog(歸檔日誌)。如果接觸mysql,那這兩個詞肯定是繞不過的,我後面的內容裡也會不斷地和你強調。不過話說回來,redo log和binlog在設計上有很多有意思的地方,這些設計思路也可以用到你自己的程式裡。

redo log

如果有人要賒賬或者還賬的話,掌櫃一般有兩種做法:

同樣,在mysql裡也有這個問題,如果每一次的更新操作都需要寫進磁碟,然後磁碟也要找到對應的那條記錄,然後再更新,整個過程io成本、查詢成本都很高。為了解決這個問題,mysql的設計者就用了類似酒店掌櫃粉板的思路來提公升更新效率。其實就是mysql裡經常說到的wal技術,wal的全稱是write-ahead logging,它的關鍵點就是先寫日誌,再寫磁碟,也就是先寫粉板,等不忙的時候再寫賬本。

redo log的特點在於它是迴圈寫的,而且有大小,4個檔案每個1g,所以當寫滿的時候,首先它會先清掉,也就是寫磁碟後再進行寫redo log。

write pos是當前記錄的位置,一邊寫一邊後移,寫到第3號檔案末尾後就回到0號檔案開頭。checkpoint是當前要擦除的位置,也是往後推移並且迴圈的,擦除記錄前要把記錄更新到資料檔案。

write pos和checkpoint之間的是「粉板」上還空著的部分,可以用來記錄新的操作。如果write pos追上checkpoint,表示「粉板」滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把checkpoint推進一下。

有了redo log,innodb就可以保證即使資料庫發生異常重啟,之前提交的記錄都不會丟失,這個能力稱為crash-safe。

bin log

mysql整體來看,其實就有兩塊:一塊是server層,它主要做的是mysql功能層面的事情;還有一塊是引擎層,負責儲存相關的具體事宜。上面我們聊到的粉板redo log是innodb引擎特有的日誌,而server層也有自己的日誌,稱為binlog(歸檔日誌)。

兩種日誌的不同

redo log是innodb引擎特有的;binlog是mysql的server層實現的,所有引擎都可以使用。

redo log是物理日誌,記錄的是「在某個資料頁上做了什麼修改」;binlog是邏輯日誌,記錄的是這個語句的原始邏輯,比如「給id=2這一行的c欄位加1 」。

redo log是迴圈寫的,空間固定會用完;binlog是可以追加寫入的。「追加寫」是指binlog檔案寫到一定大小後會切換到下乙個,並不會覆蓋以前的日誌。

update流程

執行器先找引擎取id=2這一行。id是主鍵,引擎直接用樹搜尋找到這一行。如果id=2這一行所在的資料頁本來就在記憶體中,就直接返回給執行器;否則,需要先從磁碟讀入記憶體,然後再返回。

執行器拿到引擎給的行資料,把這個值加上1,比如原來是n,現在就是n+1,得到新的一行資料,再呼叫引擎介面寫入這行新資料。

引擎將這行新資料更新到記憶體中,同時將這個更新操作記錄到redo log裡面,此時redo log處於prepare狀態。然後告知執行器執行完成了,隨時可以提交事務。

執行器生成這個操作的binlog,並把binlog寫入磁碟。

執行器呼叫引擎的提交事務介面,引擎把剛剛寫入的redo log改成提交(commit)狀態,更新完成。

將redo log的寫入拆成了兩個步驟:prepare和commit,這就是"兩階段提交"。

先寫redo log後寫binlog。假設在redo log寫完,binlog還沒有寫完的時候,mysql程序異常重啟。由於我們前面說過的,redo log寫完之後,系統即使崩潰,仍然能夠把資料恢復回來,所以恢復後這一行c的值是1。

但是由於binlog沒寫完就crash了,這時候binlog裡面就沒有記錄這個語句。因此,之後備份日誌的時候,存起來的binlog裡面就沒有這條語句。

然後你會發現,如果需要用這個binlog來恢復臨時庫的話,由於這個語句的binlog丟失,這個臨時庫就會少了這一次更新,恢復出來的這一行c的值就是0,與原庫的值不同。

先寫binlog後寫redo log。如果在binlog寫完之後crash,由於redo log還沒寫,崩潰恢復以後這個事務無效,所以這一行c的值是0。但是binlog裡面已經記錄了「把c從0改成1」這個日誌。所以,在之後用binlog來恢復的時候就多了乙個事務出來,恢復出來的這一行c的值就是1,與原庫的值不同。

簡單說,redo log和binlog都可以用於表示事務的提交狀態,而兩階段提交就是讓這兩個狀態保持邏輯上的一致。 

redo log用於保證crash-safe能力。innodb_flush_log_at_trx_commit這個引數設定成1的時候,表示每次事務的redo log都直接持久化到磁碟。這個引數我建議你設定成1,這樣可以保證mysql異常重啟之後資料不丟失。

sync_binlog這個引數設定成1的時候,表示每次事務的binlog都持久化到磁碟。這個引數我也建議你設定成1,這樣可以保證mysql異常重啟之後binlog不丟失。

1 prepare階段 2 寫binlog 3 commit

當在2之前崩潰時

重啟恢復:後發現沒有commit,回滾。備份恢復:沒有binlog 。一致

當在3之前崩潰

重啟恢復:雖沒有commit,但滿足prepare和binlog完整,所以重啟後會自動commit。備份:有binlog.。一致

參考丁奇老師《mysql實戰》

MySQL日誌系統

日誌模組 redo log 物理日誌 每次一次更新操作都需要寫進磁碟,然後磁碟也要找到對於記錄,然後在更新,整個i o成本,查詢成本都很高 innodb保證資料庫發生異常,之前的記錄也不會丟失,這個能力稱為crash safe.日誌模組 binlog 邏輯日誌 1,執行器先找到引擎id 2,id是主...

mysql系統日誌檔案 Mysql 日誌檔案系統

mysql中的日誌包括 錯誤日誌 通用查詢日誌 二進位制日誌 慢查詢日誌等等。這裡主要介紹下比較常用的兩個功能 通用查詢日誌和慢查詢日誌。錯誤日誌 記錄啟動 執行或停止mysqld時出現的問題。通用日誌 記錄建立的客戶端連線和執行的語句。二進位制日誌 記錄所有更改資料的語句。還用於複製。慢查詢日誌 ...

mysql日誌系統 SQL 邏輯日誌 物理日誌

更新語句執行的流程和查詢語句執行的流程一樣 注意 在乙個表上有更新的操作的時候,和這個表相關的查詢快取就會被清空 在經歷分析器,優化器,和執行器儲存引擎的歷程中,還多了重要的日誌模組 redo log 重做日誌 bin log 歸檔日誌 是innodb 引擎獨有的日誌模組 它的關鍵點就是更新的時候先...