研發應該懂的binlog知識(上)
引言
為什麼寫這篇文章?
大家當年在學SQL/">MySQL的時候,為了能夠迅速就業,一般是學習一下MySQL的基本語法,差不多就出山找工作了。水平稍微好一點的童鞋呢還會懂一點儲存過程的編寫,又或者是懂一點索引的建立和使用。但是呢,基本上大家都忽略了對底層知識的學習。為什麼呢?因為工作中很少用到嘛。然後呢,市面上流傳的大部分這種底層的知識,又比較偏運維,研發懂這麼多意義也不是太大,很多知識可能這輩子都不會用到。
因此,我整理了一部分相關的知識,希望大家有所收穫。
研發究竟要懂哪些?
主要分為兩個部分
- binlog 的相關概念
- 怎麼解析 binlog
計劃分上下兩個部分來敘述。上部分講述 binlog的相關概念 這部分的知識,我們不需要像運維懂的那麼深,我會列舉一些常見概念和常見配置,大家匆匆掃一眼,有個概念即可。這樣大家以後和運維討論問題的時候,也不會一臉的懵逼。正所謂
懵逼樹上懵逼果,懵逼樹下你和我。
懵逼樹前排排坐,一人一個懵逼果。
博主一個人默默的把懵逼果收走獨享就好,各位讀者還是懂點基本概念,以後方便和運維溝通。下半部分講 怎麼解析binlog 。
另外,這篇文章是給研發大大看的,可能有些概念我理解的也不對,請運維大大輕噴。
正文
記得我的"一個定義,兩個誤解,三個用途,四個常識"
一個定義
先從定義開始講起
binlog是記錄所有資料庫表結構變更(例如CREATE、ALTER TABLE…)以及表資料修改(INSERT、UPDATE、DELETE…)的二進位制日誌。
binlog不會記錄SELECT和SHOW這類操作,因為這類操作對資料本身並沒有修改,但你可以通過查詢通用日誌來檢視MySQL執行過的所有語句。
多說一句,如果 update
操作沒有造成資料變化,也是會記入 binlog
。
兩個誤解
誤解一:binlog只是一類記錄操作內容的日誌檔案
因為 binlog
稱之為二進位制日誌,很多研發會把這個 二進位制日誌 和我們平時在程式碼裡寫的 程式碼日誌 聯絡在一起。因為我們的 程式碼日誌 ,只有一類記錄操作容的檔案,並不包含索引檔案。然而,這個二進位制日誌包括兩類檔案:
- 索引檔案(檔名字尾為.index)用於記錄哪些日誌檔案正在被使用
- 日誌檔案(檔名字尾為.00000*)記錄資料庫所有的DDL和DML(除了資料查詢語句)語句事件。
這麼說可能還有一點抽象,假設檔案 my.cnf
中有這麼三條配置
log_bin:on 開啟binlog日誌 log_bin_basename:bin檔案路徑及名字首(/var/log/mysql/mysql-bin) log_bin_index:bin檔案index(/var/log/mysql/mysql-bin.index)
那麼你會在檔案目錄 /var/log/mysql/
下面發現兩個檔案 mysql-bin.000001
和 mysql-bin.index
。
mysql-bin.index
就是我們所說的索引檔案,開啟瞅瞅,內容是下面這樣,記錄哪些檔案是日誌檔案。
./mysql-bin.000001
那麼說到日誌檔案。在 innodb
裡其實又可以分為兩部分,一部分在快取中,一部分在磁碟上。這裡業內有一個詞叫做 刷盤 ,就是指將快取中的日誌刷到磁碟上。跟 刷盤 有關的引數有兩個: sync_binlog
和 binlog_cache_size
。這三個引數作用如下
binlog_cache_size: 二進位制日誌快取部分的大小,預設值32k sync_binlog=[N]: 表示寫緩衝多少次,刷一次盤,預設值為0
注意兩點:
- (1)
binlog_cache_size
設過大,會造成記憶體浪費。binlog_cache_size
設定過小,會頻繁將緩衝日誌寫入臨時檔案。具體怎麼設,有興趣自行查詢,我覺得研發大大根本沒機會去設這個值的,瞭解即可。 - (2)
sync_binlog=0
:表示重新整理binlog
時間點由作業系統自身來決定,作業系統自身會每隔一段時間就會重新整理快取資料到磁碟,這個效能最好。sync_binlog=1
,代表每次事務提交時就會重新整理binlog到磁碟。sync_binlog=N
,代表每N個事務提交會進行一次binlog重新整理。
另外,這裡存在一個一致性問題, sync_binlog=N
,資料庫在作業系統宕機的時候,可能資料並沒有同步到磁碟,於是再次重啟資料庫,會帶來資料丟失問題。
當 sync_binlog=1
,事務在 commit
的時候,資料寫入 binlog
,但是還沒寫入事務日誌( redo log
和 undo log
)。此時宕機,重啟資料庫,資料被回滾。但是 binlog
裡已經記錄,這裡存在不一致問題。這個事務日誌和 binlog
一致性的問題,大家可以查詢mysql的內部XA協議,該協議就是解決這個一致性問題的。
誤解二:binlog是InnoDb獨有的
binlog
是以事件形式記錄的,這句話通俗點說,就是 binlog
的內容都是一個個的事件。這塊具體的我會在下一篇講,這篇記住 binlog
的內容就是一個個事件就行。
注意了,這裡的用詞,是一個個事件,而不是事務。大家應該知道 Innodb
和 mysiam
最顯著的區別就是一個支援事務,一個不支援事務。
因此你可以說, binlog
是基於事務來記錄二進位制日誌,比如 sync_binlog=1
,每提交一次事務,就寫入 binlog
。你卻不能說 binlog
是事務日誌, binlog
不僅記錄 innodb
日誌,在 myisam
中,也一樣存在 binlog
。
三個用途
這三個用途,出自《MySQL技術內幕 InnoDB儲存引擎》一書,分別為 恢復 、 複製 、 審計 。這三個用途,研發大大們瞭解一下即可,比如資料恢復,你碰到同事刪庫的機會實在太少。假如真的有同事捨己為人,冒著離職的風險給你提供做資料 恢復 的機會,大把運維工程師待命在那,輪不到你的。所以,這三個功能瞭解即可。
恢復:這裡網上有大把的文章指導你,如何利用 binlog
日誌恢復資料庫資料。如果你真的覺得自己很有時間,就自己去建立個庫,然後刪了,再去恢復一下資料,練練手吧。
複製: 如圖所示(圖片不是自己畫的,偷懶了)

主庫有一個 log dump
執行緒,將 binlog
傳給從庫
從庫有兩個執行緒,一個I/O執行緒,一個SQL執行緒,I/O執行緒讀取主庫傳過來的 binlog
內容並寫入到 relay log
,SQL執行緒從 relay log
裡面讀取內容,寫入從庫的資料庫。
審計:使用者可以通過二進位制日誌中的資訊來進行審計,判斷是否有對資料庫進行注入攻擊。
四個常識
常識一:binlog常見格式
這塊知識我用一個表格來表示,沒必要囉嗦一大堆。
format | 定義 | 優點 | 缺點 |
---|---|---|---|
statement | 記錄的是修改SQL語句 | 日誌檔案小,節約IO,提高效能 | 準確性差,對一些系統函式不能準確複製或不能複製,如now()、uuid()等 |
row | 記錄的是每行實際資料的變更 | 準確性強,能準確複製資料的變更 | 日誌檔案大,較大的網路IO和磁碟IO |
mixed | statement和row模式的混合 | 準確性強,檔案大小適中 | 有可能發生主從不一致問題 |
業內目前推薦使用的是 row
模式,準確性高,雖然說檔案大,但是現在有SSD和萬兆光纖網路,這些磁碟IO和網路IO都是可以接受的。
那麼,大家一定想問,為什麼不推薦使用 mixed
模式,理由如下
假設master有兩條記錄,而slave只有一條記錄。
master的資料為
+----+------------------------------------------------------+ | id | n | +----+------------------------------------------------------+ | 1 | d24c2c7e-430b-11e7-bf1b-00155d016710 | | 2 | ddd | +----+------------------------------------------------------+
slave的資料為
+----+-------------------------------------------------------+ | id | n | +----+-------------------------------------------------------+ | 1 | d24c2c7e-430b-11e7-bf1b-00155d016710 | +----+-------------------------------------------------------+
當在 master
上更新一條從庫不存在的記錄時,也就是 id=2
的記錄,你會發現 master
是可以執行成功的。而 slave
拿到這個SQL後,也會照常執行,不報任何異常,只是更新操作不影響行數而已。並且你執行命令 show slave status
,檢視輸出,你會發現沒有異常。但是,如果你是 row
模式,由於這行根本不存在,是會報1062錯誤的。
常識二:怎檢視binlog
binlog
本身是一類二進位制檔案。二進位制檔案更省空間,寫入速度更快,是無法直接開啟來檢視的。
因此mysql提供了命令 mysqlbinlog
進行檢視。
一般的 statement
格式的二進位制檔案,用下面命令就可以
mysqlbinlog mysql-bin.000001
如果是 row
格式,加上 -v
或者 -vv
引數就行,如
mysqlbinlog -vv mysql-bin.000001
常識三:怎麼刪binlog
刪 binlog
的方法很多,有三種是常見的
(1) 使用 reset master
,該命令將會刪除所有日誌,並讓日誌檔案重新從000001開始。
(2) 使用命令
PURGE { BINARY | MASTER } LOGS { TO 'log_name' | BEFORE datetime_expr }
例如
purge master logs to "binlog_name.00000X"
將會清空00000X之前的所有日誌檔案.
(3) 使用 --expire_logs_days=N
選項指定過了多少天日誌自動過期清空。
常識四:binlog常見引數
常見引數,列舉如下,有個印象就好。
引數名 | 含義 |
---|---|
log_bin = {on | off | base_name} | 指定是否啟用記錄二進位制日誌或者指定一個日誌路徑 |
sql_log_bin ={ on | off } | 指定是否啟用記錄二進位制日誌 |
expire_logs_days | 指定自動刪除二進位制日誌的時間,即日誌過期時間 |
log_bin_index | 指定mysql-bin.index檔案的路徑 |
binlog_format = { mixed | row | statement } | 指定二進位制日誌基於什麼模式記錄 |
max_binlog_size | 指定二進位制日誌檔案最大值 |
binlog_cache_size | 指定事務日誌快取區大小 |
max_binlog_cache_size | 指定二進位制日誌快取最大大小 |
sync_binlog = { 0 | n } | 指定寫緩衝多少次,刷一次盤 |
思考題
請問,我說的
- 一個定義
- 兩個誤解
- 三個用途
- 四個常識
說的是什麼呢?
另外,我會在下一篇進行介紹,怎麼用程式碼解析 binlog
日誌。