1. 程式人生 > >【原創】研發應該懂的binlog知識(上)

【原創】研發應該懂的binlog知識(上)

引言

為什麼寫這篇文章?

大家當年在學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.000001mysql-bin.indexmysql-bin.index就是我們所說的索引檔案,開啟瞅瞅,內容是下面這樣,記錄哪些檔案是日誌檔案。

./mysql-bin.000001

那麼說到日誌檔案。在innodb裡其實又可以分為兩部分,一部分在快取中,一部分在磁碟上。這裡業內有一個詞叫做刷盤,就是指將快取中的日誌刷到磁碟上。跟刷盤有關的引數有兩個:sync_binlogbinlog_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 logundo log)。此時宕機,重啟資料庫,資料被回滾。但是binlog裡已經記錄,這裡存在不一致問題。這個事務日誌和binlog一致性的問題,大家可以查詢mysql的內部XA協議,該協議就是解決這個一致性問題的。

誤解二:binlog是InnoDb獨有的 binlog是以事件形式記錄的,這句話通俗點說,就是binlog的內容都是一個個的事件。這塊具體的我會在下一篇講,這篇記住binlog的內容就是一個個事件就行。 注意了,這裡的用詞,是一個個事件,而不是事務。大家應該知道Innodbmysiam最顯著的區別就是一個支援事務,一個不支援事務。 因此你可以說,binlog是基於事務來記錄二進位制日誌,比如sync_binlog=1,每提交一次事務,就寫入binlog。你卻不能說binlog是事務日誌,binlog不僅記錄innodb日誌,在myisam中,也一樣存在binlog

三個用途

這三個用途,出自《MySQL技術內幕 InnoDB儲存引擎》一書,分別為恢復複製審計。這三個用途,研發大大們瞭解一下即可,比如資料恢復,你碰到同事刪庫的機會實在太少。假如真的有同事捨己為人,冒著離職的風險給你提供做資料恢復的機會,大把運維工程師待命在那,輪不到你的。所以,這三個功能瞭解即可。

恢復:這裡網上有大把的文章指導你,如何利用binlog日誌恢復資料庫資料。如果你真的覺得自己很有時間,就自己去建立個庫,然後刪了,再去恢復一下資料,練練手吧。

複製: 如圖所示(圖片不是自己畫的,偷懶了) image 主庫有一個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 

常識三:怎麼刪binlogbinlog的方法很多,有三種是常見的

(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日誌。