不會吧,不會吧,還有人不知道 binlog ?

redo log它是物理日誌,記錄內容是“在某個數據頁上做了什麼修改”,屬於InnoDB存儲引擎。

binlog是邏輯日誌,記錄內容是語句的原始邏輯,類似於“給ID=2這一行的c字段加1”,屬於MySQL Server層。

binlog

不管用什麼存儲引擎,只要發生了表數據更新,都會產生binlog日誌。

binlog到底是用來幹嘛的?

可以說MySQL數據庫的數據備份、主備、主主、主從都離不開binlog,需要依靠binlog來同步數據,保證數據一致性。


binlog會記錄所有涉及更新數據的邏輯操作,並且是順序寫。

記錄格式

binlog日誌有三種格式,可以通過binlog_format參數指定。

  • statement

  • row

  • mixed

指定statement,記錄的內容是SQL語句原文,比如執行一條update T set update_time=now() where id=1,記錄的內容如下。

同步數據時,會執行記錄的SQL語句,但是有個問題,update_time=now()這裏會獲取當前系統時間,直接執行會導致與原庫的數據不一致。

爲了解決這種問題,我們需要指定爲row,記錄的內容不再是簡單的SQL語句了,還包含操作的具體數據,記錄內容如下。

row格式記錄的內容看不到詳細信息,要通過mysqlbinlog工具解析出來。

update_time=now()變成了具體的時間update_time=1627112756247,條件後面的@1、@2、@3都是該行數據第1個~3個字段的原始值(假設這張表只有3個字段)。

這樣就能保證同步數據的一致性,通常情況下都是指定爲row,這樣可以爲數據庫的恢復與同步帶來更好的可靠性。

但是這種格式,需要更大的容量來記錄,比較佔用空間,恢復與同步時會更消耗IO資源,影響執行速度。

所以就有了一種折中的方案,指定爲mixed,記錄的內容是前兩者的混合。

MySQL會判斷這條SQL語句是否可能引起數據不一致,如果是,就用row格式,否則就用statement格式。

寫入機制

binlog的寫入時機也非常簡單,事務執行過程中,先把日誌寫到binlog cache,事務提交的時候,再把binlog cache寫到binlog文件中。

因爲一個事務的binlog不能被拆開,無論這個事務多大,也要確保一次性寫入,所以系統會給每個線程分配一個塊內存作爲binlog cache

我們可以通過binlog_cache_size參數控制單個線程binlog cache大小,如果存儲內容超過了這個參數,就要暫存到磁盤(Swap)。

binlog日誌刷盤流程如下


  • 上圖的write,是指把日誌寫入到文件系統的page cache,並沒有把數據持久化到磁盤,所以速度比較快

  • 上圖的fsync,纔是將數據持久化到磁盤的操作

writefsync的時機,可以由參數sync_binlog控制,默認是0

0的時候,表示每次提交事務都只write,由系統自行判斷什麼時候執行fsync

雖然性能得到提升,但是機器宕機,page cache裏面的binglog會丟失。

爲了安全起見,可以設置爲1,表示每次提交事務都會執行fsync,就如同binlog日誌刷盤流程一樣。

最後還有一種折中方式,可以設置爲N(N>1),表示每次提交事務都write,但累積N個事務後才fsync

在出現IO瓶頸的場景裏,將sync_binlog設置成一個比較大的值,可以提升性能。

同樣的,如果機器宕機,會丟失最近N個事務的binlog日誌。


有道無術,術可成;有術無道,止於術

歡迎大家關注Java之道公衆號


好文章,我在看❤️

本文分享自微信公衆號 - Hollis(hollischuang)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章