不會吧,不會吧,還有人不知道 binlog ?
前言
上篇阿星詳細聊了 redo log
(重做日誌),但是在MySQL
數據庫中還有一種二進制日誌叫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,纔是將數據持久化到磁盤的操作
write
和fsync
的時機,可以由參數sync_binlog
控制,默認是0
。
爲0
的時候,表示每次提交事務都只write
,由系統自行判斷什麼時候執行fsync
。
雖然性能得到提升,但是機器宕機,page cache
裏面的binglog
會丟失。
爲了安全起見,可以設置爲1
,表示每次提交事務都會執行fsync
,就如同 binlog 日誌刷盤流程一樣。
最後還有一種折中方式,可以設置爲N(N>1)
,表示每次提交事務都write
,但累積N
個事務後才fsync
。
在出現IO
瓶頸的場景裏,將sync_binlog
設置成一個比較大的值,可以提升性能。
同樣的,如果機器宕機,會丟失最近N
個事務的binlog
日誌。
站在巨人的肩膀上
-
《MySQL 實戰 45 講》
-
《從零開始帶你成爲 MySQL 實戰優化高手》
-
《MySQL 技術 Innodb 存儲引擎》
關於我
阿星是一個熱愛技術的 Java
程序猿,公衆號**「程序猿阿星」** 定期分享有趣有料的精品原創文章!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/W-u9l_As2pLUMlSQFTckCQ