單點突破 MySQL之日誌

2022-06-23 13:57:12 字數 4720 閱讀 3136

開發環境:mysql5.7.31

日誌是 mysql 資料庫的重要組成部分,記錄著資料庫執行期間各種狀態資訊。若資料庫發生故障,可通過不同日誌記錄恢復資料庫的原來資料。因此實際上日誌系統直接決定著mysql執行的魯棒性和穩健性。mysql中有六種日誌檔案,分別是:重做日誌(redo log)、回滾日誌(undo log)、二進位制日誌(binlog)、錯誤日誌(errorlog)、慢查詢日誌(slow query log)、一般查詢日誌(general log),中繼日誌(relay log)。

其中開發中比較關注的是重做日誌(redo log)、回滾日誌(undo log)、二進位制日誌(binlog),它們也是面試中關於mysql日誌的常客。

重做日誌(redo log)是innodb引擎層的日誌,用來記錄事務操作引起資料的變化,記錄的是資料頁的物理修改。作用是:確保事務的永續性。防止在發生故障的時間點,尚有髒頁未寫入磁碟,在重啟mysql服務的時候,根據redo log進行重做,從而達到事務的永續性這一特性。

在 mysql 中,如果每一次的更新操作都需要寫進磁碟,然後磁碟也要找到對應的那條記錄,然後再更新,整個過程 io 成本、查詢成本都很高。為了解決這個問題,mysql 的設計者就採用了日誌(redo log)來提公升更新效率。

而日誌和磁碟配合的整個過程,其實就是 mysql 裡的 wal 技術,wal 的全稱是 write-ahead logging,這就是所謂的預寫式技術,它的關鍵點就是先寫日誌,再寫磁碟這種技術可以大大減少io操作的頻率,提公升資料重新整理的效率。

具體來說,當有一條記錄需要更新的時候,innodb 引擎就會先把記錄寫到 redo log(redolog buffer)裡面,並更新記憶體(buffer pool),這個時候更新就算完成了。同時,innodb 引擎會在適當的時候(如系統空閒時),將這個操作記錄更新到磁碟裡面(刷髒頁)。

我們都知道,事務的四大特性裡面有乙個是永續性,具體來說就是只要事務提交成功,那麼對資料庫做的修改就被永久儲存下來了,不可能因為任何原因再回到原來的狀態。

那麼mysql是如何保證一致性的呢?

最簡單的做法是在每次事務提交的時候,將該事務涉及修改的資料頁全部重新整理到磁碟中。但是這麼做會有嚴重的效能問題,主要體現在兩個方面:

因此 mysql 設計了 redo log ,具體來說就是只記錄事務對資料頁做了哪些修改,這樣就能完美地解決效能問題了(相對而言檔案更小並且是順序io)。

redo log 包括兩部分:乙個是記憶體中的日誌緩衝( redo log buffer),另乙個是磁碟上的日誌檔案(redo logfile)。

mysql 每執行一條 dml 語句,先將記錄寫入 redo log buffer,後續某個時間點再一次性將多個操作記錄寫到 redo log file。這種技術就是上文提到的 wal(write-ahead logging) 技術。

在計算機作業系統中,使用者空間( user space )下的緩衝區資料一般情況下是無法直接寫入磁碟的,中間必須經過作業系統核心空間( kernel space )緩衝區( os buffer )。因此, redo log buffer 寫入 redo logfile 實際上是先寫入 os buffer ,然後再通過系統呼叫 fsync() 將其刷到 redo log file中,具體如下圖:

看起來很複雜,但只要記住redo log是先寫日誌再寫磁碟就行,這些只是redo log的執行過程,而且上述的過程更接近髒日誌刷盤,如果看不明白上面的知識,我們下面從兩個方面展開說明redo log

我們上面說到的過程就是髒日誌刷盤,上文提到了幾個概念,這裡做一些補充:

為了確保每次記錄都能夠寫入到磁碟中的日誌中,每次將redo log buffer中的日誌寫入redo log file的過程中都會呼叫一次作業系統的fsync操作。在寫入的過程中,還需要經過作業系統核心空間的os buffer。也就是我們上圖的操作了。

髒資料:指記憶體中未刷到磁碟的資料。

redo log的記錄形式如下:

redo log 實際上記錄資料頁的變更,而這種變更記錄是沒必要全部儲存,因此 redo log實現上採用了大小固定,迴圈寫入的方式,當寫到結尾時,會回到開頭迴圈寫日誌。

redo log日誌的大小是固定的,為了能夠持續不斷的對更新記錄進行寫入,在redo log日誌中設定了兩個標誌位置,checkpoint和write_pos,分別表示記錄擦除的位置和記錄寫入的位置。

redo log中最重要的概念就是緩衝池buffer pool,這是在記憶體中分配的乙個區域,包含了磁碟中部分資料頁的對映,作為訪問資料庫的緩衝。

因此,當資料修改時,除了修改buffer pool中的資料,還會在redo log中記錄這次操作;當事務提交時,會根據redo log的記錄對資料進行刷盤。如果mysql宕機,重啟時可以讀取redo log中的資料,對資料庫進行恢復,從而保證了事務的永續性,使得資料庫獲得crash-safe能力。

二進位制日誌binlog是服務層的日誌,還被稱為歸檔日誌。binlog主要記錄資料庫的變化情況,內容包括資料庫所有的更新操作。所有涉及資料變動的操作,都要記錄進二進位制日誌中,以二進位制的形式儲存在磁碟中。因此有了binlog可以很方便的對資料進行複製和備份,因而也常用作主從庫的同步

binlog 是 mysql的邏輯日誌,並且由 server 層進行記錄,使用任何儲存引擎的 mysql 資料庫都會記錄 binlog 日誌。

binlog 是通過追加的方式進行寫入的,可以通過max_binlog_size 引數設定每個 binlog檔案的大小,當檔案大小達到給定值之後,會生成新的檔案來儲存日誌。

在實際應用中, binlog 的主要使用場景有兩個,分別是主從複製資料恢復

binlog 日誌有三種格式,分別為 statment 、 row 和 mixed。

在 mysql 5.7.7 之前,預設的格式是 statement , mysql 5.7.7 之後,預設值是 row。日誌格式通過 binlog-format 指定。

row:基於行的複製(row-based replication, rbr ),不記錄每條sql語句的上下文資訊,僅需記錄哪條資料被修改了 。

mixed:基於statment 和 row 兩種模式的混合複製(mixed-based replication, mbr ),一般的複製使用statement 模式儲存 binlog ,對於 statement 模式無法複製的操作使用 row 模式儲存 binlog

在mysql執行更新語句時,都會涉及到redo log日誌和binlog日誌的讀寫。一條更新語句的執行過程如下:

從上圖可以看出,mysql在執行更新語句的時候,在服務層進行語句的解析和執行,在引擎層進行資料的提取和儲存;同時在服務層對binlog進行寫入,在innodb內進行redo log的寫入。不僅如此,在對redo log寫入時有兩個階段的提交,一是binlog寫入之前prepare狀態的寫入,二是binlog寫入之後commit狀態的寫入。兩階段提交可以保證binlog和redo log中儲存的資訊是一致的。

這裡binlog所儲存的內容看起來似乎與redo log很相似,但是其實不然。redo log是一種物理日誌,記錄的是實際上對某個資料進行了怎麼樣的修改;而binlog是邏輯日誌,記錄的是sql語句的原始邏輯,比如」給id=2這一行的a欄位加1 "。binlog日誌中的內容是二進位制的,根據日記格式引數的不同,可能基於sql語句、基於資料本身或者二者的混合。一般常用記錄的都是sql語句。

同時,redo log是基於crash recovery,保證mysql宕機後的資料恢復;而binlog是基於point-in-time recovery,保證伺服器可以基於時間點對資料進行恢復,或者對資料進行備份。

總的來說,兩者的區別可以歸納如下:

對引擎的支援

檔案空間

寫入方式

由 binlog 和 redo log 的區別可知:binlog 日誌只用於歸檔,只依靠 binlog 是沒有 crash-safe 能力的。

但只有 redo log 也不行,因為 redo log 是 innodb特有的,且日誌上的記錄落盤後會被覆蓋掉。因此需要 binlog和 redo log二者同時記錄,才能保證當資料庫發生宕機重啟時,資料不會丟失。

回滾日誌同樣也是innodb引擎提供的日誌,顧名思義,回滾日誌的作用就是對資料進行回滾。當事務對資料庫進行修改,innodb引擎不僅會記錄redo log,還會生成對應的undo log日誌;如果事務執行失敗或呼叫了rollback,導致事務需要回滾,就可以利用undo log中的資訊將資料回滾到修改之前的樣子。

但是undo log不redo log不一樣,它屬於邏輯日誌。它對sql語句執行相關的資訊進行記錄。當發生回滾時,innodb引擎會根據undo log日誌中的記錄做與之前相反的工作。比如對於每個資料插入操作(insert),回滾時會執行資料刪除操作(delete);對於每個資料刪除操作(delete),回滾時會執行資料插入操作(insert);對於每個資料更新操作(update),回滾時會執行乙個相反的資料更新操作(update),把資料改回去。undo log由兩個作用,一是提供回滾,二是實現mvcc。

Mysql系列之 日誌

tip 生活不易,碼農辛苦 我是小刀,在網際網路中夾縫求生 我希望你開心 redo log 重做日誌 和binlog 歸檔日誌 redo log 像一塊 粉板 更新的時候,先寫到 redo log 和記憶體裡,這次更新就算是結束了。等到合適的時機再寫到磁碟裡,大大減小了寫磁碟的次數。redo log...

mysql 日記 mysql之日誌

我是李福春,我在準備面試,今天的題目是 mysql的redolog和binlog有什麼區別?答 如下面的 然後我們擴充套件一下,因為日誌主要是記錄的修改日誌,分別加深分析一下 redolog redolog是innodb儲存引擎特有的物理日誌,記錄的是資料頁做了什麼改動。它的儲存空間是固定的,類似乙...

mysql日誌恢復 Mysql之日誌恢復

對於mysql,每一步操作都會有相應記錄,如insert,update,delete drop alter等相關ddl或dml操作。有時難免會出錯,但在出錯時如何恢復以復原資料。例如,現在有這些資料 但被我truncate了。需要緊急恢復。首先,確保開啟了binlog輸出 然後,找到當前日誌檔案,使...