Mysql binlog是二進(jìn)制日志文件,用于記錄mysql的數(shù)據(jù)更新或者潛在更新(比如DELETE語(yǔ)句執(zhí)行刪除而實(shí)際并沒有符合條件的數(shù)據(jù)),在mysql主從復(fù)制中就是依靠的binlog??梢酝ㄟ^語(yǔ)句“show binlog events in 'binlogfile'”來查看binlog的具體事件類型。binlog記錄的所有操作實(shí)際上都有對(duì)應(yīng)的事件類型的,MySQL binlog的三種工作模式:
(1)Row level(用到MySQL的特殊功能如存儲(chǔ)過程、觸發(fā)器、函數(shù),又希望數(shù)據(jù)最大化一直則選擇Row模式,我們公司選擇的是row)
簡(jiǎn)介:日志中會(huì)記錄每一行數(shù)據(jù)被修改的情況,然后在slave端對(duì)相同的數(shù)據(jù)進(jìn)行修改。
優(yōu)點(diǎn):能清楚的記錄每一行數(shù)據(jù)修改的細(xì)節(jié)
缺點(diǎn):數(shù)據(jù)量太大
(2)Statement level(默認(rèn))
簡(jiǎn)介:每一條被修改數(shù)據(jù)的sql都會(huì)記錄到master的bin-log中,slave在復(fù)制的時(shí)候sql進(jìn)程會(huì)解析成和原來master端執(zhí)行過的相同的sql再次執(zhí)行。在主從同步中一般是不建議用statement模式的,因?yàn)闀?huì)有些語(yǔ)句不支持,比如語(yǔ)句中包含UUID函數(shù),以及LOAD DATA IN FILE語(yǔ)句等
優(yōu)點(diǎn):解決了 Row level下的缺點(diǎn),不需要記錄每一行的數(shù)據(jù)變化,減少bin-log日志量,節(jié)約磁盤IO,提高新能
缺點(diǎn):容易出現(xiàn)主從復(fù)制不一致
(3)Mixed(混合模式)
簡(jiǎn)介:結(jié)合了Row level和Statement level的優(yōu)點(diǎn),同時(shí)binlog結(jié)構(gòu)也更復(fù)雜。
binlog結(jié)構(gòu)解析
binlog結(jié)構(gòu)圖如下:

binlog類似字節(jié)碼一樣定義了很多種類型,每個(gè)類型又有特定的結(jié)構(gòu)。查看Mysql源碼(mysql-5.7.14/libbinlogevents/include/binlog_event.h)對(duì)event類型的定義如下:
enum Log_event_type
{
/**
Every time you update this enum (when you add a type), you have to
fix Format_description_event::Format_description_event().
*/
UNKNOWN_EVENT= 0,
START_EVENT_V3= 1,
QUERY_EVENT= 2,
STOP_EVENT= 3,
ROTATE_EVENT= 4,
INTVAR_EVENT= 5,
LOAD_EVENT= 6,
SLAVE_EVENT= 7,
CREATE_FILE_EVENT= 8,
APPEND_BLOCK_EVENT= 9,
EXEC_LOAD_EVENT= 10,
DELETE_FILE_EVENT= 11,
/**
NEW_LOAD_EVENT is like LOAD_EVENT except that it has a longer
sql_ex, allowing multibyte TERMINATED BY etc; both types share the
same class (Load_event)
*/
NEW_LOAD_EVENT= 12,
RAND_EVENT= 13,
USER_VAR_EVENT= 14,
FORMAT_DESCRIPTION_EVENT= 15,
XID_EVENT= 16,
BEGIN_LOAD_QUERY_EVENT= 17,
EXECUTE_LOAD_QUERY_EVENT= 18,
TABLE_MAP_EVENT = 19,
/**
The PRE_GA event numbers were used for 5.1.0 to 5.1.15 and are
therefore obsolete.
*/
PRE_GA_WRITE_ROWS_EVENT = 20,
PRE_GA_UPDATE_ROWS_EVENT = 21,
PRE_GA_DELETE_ROWS_EVENT = 22,
/**
The V1 event numbers are used from 5.1.16 until mysql-trunk-xx
*/
WRITE_ROWS_EVENT_V1 = 23,
UPDATE_ROWS_EVENT_V1 = 24,
DELETE_ROWS_EVENT_V1 = 25,
/**
Something out of the ordinary happened on the master
*/
INCIDENT_EVENT= 26,
/**
Heartbeat event to be send by master at its idle time
to ensure master's online status to slave
*/
HEARTBEAT_LOG_EVENT= 27,
/**
In some situations, it is necessary to send over ignorable
data to the slave: data that a slave can handle in case there
is code for handling it, but which can be ignored if it is not
recognized.
*/
IGNORABLE_LOG_EVENT= 28,
ROWS_QUERY_LOG_EVENT= 29,
/** Version 2 of the Row events */
WRITE_ROWS_EVENT = 30,
UPDATE_ROWS_EVENT = 31,
DELETE_ROWS_EVENT = 32,
GTID_LOG_EVENT= 33,
ANONYMOUS_GTID_LOG_EVENT= 34,
PREVIOUS_GTIDS_LOG_EVENT= 35,
TRANSACTION_CONTEXT_EVENT= 36,
VIEW_CHANGE_EVENT= 37,
/* Prepared XA transaction terminal event similar to Xid */
XA_PREPARE_LOG_EVENT= 38,
/**
Add new events here - right above this comment!
Existing events (except ENUM_END_EVENT) should never change their numbers
*/
ENUM_END_EVENT /* end marker */
};
下面描述幾個(gè)重要的EVENT類型:
QUERY_EVENT
QUERY_EVENT以文本的形式來記錄事務(wù)的操作。QUERY_EVENT類型的事件通常在以下幾種情況下使用:
- 事務(wù)開始時(shí),執(zhí)行的BEGIN操作。
- STATEMENT格式中的DML操作。
- ROW格式中的DDL操作。
固定數(shù)據(jù)部分:
- 4字節(jié)表示發(fā)起這個(gè)語(yǔ)句的線程id,對(duì)于臨時(shí)表來說是必須的。這也有助于DBA知道誰(shuí)在master上干了啥。
- 4字節(jié)表示語(yǔ)句執(zhí)行的時(shí)長(zhǎng),單位為秒。只對(duì)于DBA的監(jiān)控有用。
- 1字節(jié)表示語(yǔ)句執(zhí)行對(duì)應(yīng)的數(shù)據(jù)庫(kù)名稱的長(zhǎng)度。名稱在可變數(shù)據(jù)部分。
- 2字節(jié)表示在master執(zhí)行語(yǔ)句的錯(cuò)誤碼。錯(cuò)誤碼定義在include/mysqld_error.h文件中。0表示沒有錯(cuò)誤。
- 2字節(jié)表示狀態(tài)變量長(zhǎng)度。
可變數(shù)據(jù)部分:
- 大于等于0的狀態(tài)變量。每個(gè)狀態(tài)變量包含一個(gè)字節(jié)碼,標(biāo)識(shí)存儲(chǔ)變量,后面跟著變量的值。變量的值的字節(jié)長(zhǎng)度是根據(jù)變量規(guī)定好的。詳見下面變量說明
- 默認(rèn)數(shù)據(jù)庫(kù)名
- SQL語(yǔ)句。slave知道變量中其他字段的長(zhǎng)度,所以通過減法計(jì)算,可以知道語(yǔ)句的長(zhǎng)度。
下面的列表提供了每個(gè)變量的基本信息:
- Q_FLAGS2_CODE=0。值為一個(gè)4字節(jié)的位字段。這個(gè)變量只會(huì)在5.0中寫入。
- Q_SQL_MODE_CODE = 1。 他是一個(gè)每一位代表SQL_MODE中的一個(gè)值,參考最后源碼的解釋。
- Q_CATALOG_CODE = 2.。只在MYSQL 5.0.0到5.0.3使用不考慮
- Q_AUTO_INCREMENT = 3。 2 bytes非負(fù)整數(shù)用于表示參數(shù)auto_increment_increment和auto_increment_offset,這個(gè)只會(huì)在auto_increment大于1的時(shí)候出現(xiàn)。
- Q_CHARSET_CODE = 4。 6 bytes用于表示character_set_client,collation_connection和collation_server參數(shù)(totally 2+2+2=6 bytes)參考最后源碼解釋
- Q_TIME_ZONE_CODE = 5。用于描述time zone信息
- Q_CATALOG_NZ_CODE = 6。用于描述catalog name,長(zhǎng)度占用一個(gè)字節(jié),隨后這個(gè)值為std
- Q_LC_TIME_NAMES_CODE = 7。 2 bytes 非負(fù)整數(shù),只有當(dāng)lc_time_names不設(shè)置為en_US的時(shí)候使用
- Q_CHARSET_DATABASE_CODE = 8。2 bytes 非負(fù)整數(shù)為collation_database系統(tǒng)變量,5.7源碼解釋說這部分新版本不一定使用。
- Q_TABLE_MAP_FOR_UPDATE_CODE = 9。
FORMAT_DESCRIPTION_EVENT
FORMAT_DESCRIPTION_EVENT是binlog version 4中為了取代之前版本中的START_EVENT_V3事件而引入的。它是binlog文件中的第一個(gè)事件,而且,該事件只會(huì)在binlog中出現(xiàn)一次。MySQL根據(jù)FORMAT_DESCRIPTION_EVENT的定義來解析其它事件。
它通常指定了MySQL Server的版本,binlog的版本,該binlog文件的創(chuàng)建時(shí)間。
固定數(shù)據(jù)部分:
- 2字節(jié)表示binlog格式版本,對(duì)于5.0及以上版本,是4.
- 50字節(jié)表示Mysql服務(wù)器版本,后面帶著0x00。
- 4字節(jié)表示事件創(chuàng)建的時(shí)間戳。多余的參數(shù),和頭中的時(shí)間戳重復(fù)。
- 1字節(jié)表示頭長(zhǎng)度。當(dāng)前的值為19.
可變數(shù)據(jù)部分:
- 空。
ROWS_EVENT
對(duì)于ROW格式的binlog,所有的DML語(yǔ)句都是記錄在ROWS_EVENT中。
ROWS_EVENT分為三種:WRITE_ROWS_EVENT,UPDATE_ROWS_EVENT,DELETE_ROWS_EVENT,分別對(duì)應(yīng)insert,update和delete操作。
對(duì)于insert操作,WRITE_ROWS_EVENT包含了要插入的數(shù)據(jù)
對(duì)于update操作,UPDATE_ROWS_EVENT不僅包含了修改后的數(shù)據(jù),還包含了修改前的值。
對(duì)于delete操作,僅僅需要指定刪除的主鍵(在沒有主鍵的情況下,會(huì)給定所有列)
對(duì)于QUERY_EVENT事件,是以文本形式記錄DML操作的。而對(duì)于ROWS_EVENT事件,并不是文本形式,所以在通過mysqlbinlog查看基于ROW格式的binlog時(shí),需要指定-vv --base64-output=decode-rows。
XID_EVENT
在事務(wù)提交時(shí),不管是STATEMENT還是ROW格式的binlog,都會(huì)在末尾添加一個(gè)XID_EVENT事件代表事務(wù)的結(jié)束。該事件記錄了該事務(wù)的ID,在MySQL進(jìn)行崩潰恢復(fù)時(shí),根據(jù)事務(wù)在binlog中的提交情況來決定是否提交存儲(chǔ)引擎中狀態(tài)為prepared的事務(wù)。
固定數(shù)據(jù)部分:
- 空
可變數(shù)據(jù)部分:
- 8字節(jié),XID事務(wù)號(hào)
ROTATE_EVENT
當(dāng)binlog文件的大小達(dá)到max_binlog_size的值或者執(zhí)行flush logs命令時(shí),binlog會(huì)發(fā)生切換,這個(gè)時(shí)候會(huì)在當(dāng)前的binlog日志添加一個(gè)ROTATE_EVENT事件,用于指定下一個(gè)日志的名稱和位置。
固定數(shù)據(jù)部分:
- 8字節(jié)。下個(gè)日志文件的第一個(gè)事件的位置。經(jīng)常包含數(shù)字4(表示下個(gè)binlog的下個(gè)事件從位置4開始)。這個(gè)字段在v1中不存在??梢酝茰y(cè),這個(gè)值是4。
可變數(shù)據(jù)部分: - 下個(gè)binlog文件的名字。文件名不是以null結(jié)尾的,他的長(zhǎng)度是事件長(zhǎng)度-固定數(shù)據(jù)長(zhǎng)度。
GTID_LOG_EVENT
GTID即全局事務(wù)ID(global transaction identifier)是Mysql5.6版本引入的,GTID實(shí)際上是由UUID+TID組成的。其中UUID是一個(gè)MySQL實(shí)例的唯一標(biāo)識(shí)。TID代表了該實(shí)例上已經(jīng)提交的事務(wù)數(shù)量,并且隨著事務(wù)提交單調(diào)遞增,所以GTID能夠保證每個(gè)MySQL實(shí)例事務(wù)的執(zhí)行(不會(huì)重復(fù)執(zhí)行同一個(gè)事務(wù),并且會(huì)補(bǔ)全沒有執(zhí)行的事務(wù))。在啟用GTID模式后,MySQL實(shí)際上為每個(gè)事務(wù)都分配了個(gè)GTID。
譬如:
# at 448
#160818 5:37:32 server id 1 end_log_pos 496 CRC32 0xaeb24aac GTID [commit=yes]
SET @@SESSION.GTID_NEXT= 'cad449f2-5d4f-11e6-b353-000c29c64704:3'/*!*/;
# at 496
#160818 5:37:32 server id 1 end_log_pos 571 CRC32 0x042ca092 Query thread_id=2 exec_time=0 error_code=0
SET TIMESTAMP=1471469852/*!*/;
BEGIN
/*!*/;
# at 571
#160818 5:37:32 server id 1 end_log_pos 674 CRC32 0xa35beb37 Query thread_id=2 exec_time=0 error_code=0
SET TIMESTAMP=1471469852/*!*/;
insert into test.t1 values(2,'b')
/*!*/;
# at 674
#160818 5:37:32 server id 1 end_log_pos 705 CRC32 0x1905d8c6 Xid = 12
COMMIT/*!*/;
PREVIOUS_GTIDS_LOG_EVENT
開啟GTID模式后,每個(gè)binlog開頭都會(huì)有一個(gè)PREVIOUS_GTIDS_LOG_EVENT事件,它的值是上一個(gè)binlog的PREVIOUS_GTIDS_LOG_EVENT+GTID_LOG_EVENT,實(shí)際上,在數(shù)據(jù)庫(kù)重啟的時(shí)候,需要重新填充gtid_executed的值,該值即是最新一個(gè)binlog的PREVIOUS_GTIDS_LOG_EVENT+GTID_LOG_EVENT。
mysql-bin.000033日志中的Previous_gtids是cad449f2-5d4f-11e6-b353-000c29c64704:1,GTID是cad449f2-5d4f-11e6-b353-000c29c64704:2和cad449f2-5d4f-11e6-b353-000c29c64704:3,這樣,在下一個(gè)日志,即mysql-bin.000034中的Previous_gtids是cad449f2-5d4f-11e6-b353-000c29c64704:1-3。
STOP_EVENT
當(dāng)MySQL數(shù)據(jù)庫(kù)停止時(shí),會(huì)在當(dāng)前的binlog末尾添加一個(gè)STOP_EVENT事件表示數(shù)據(jù)庫(kù)停止。
固定數(shù)據(jù)部分:
- 空
可變數(shù)據(jù)部分: - 空
HEARTBEAT_LOG_EVENT
這個(gè)事件是由master發(fā)給slave的,讓slave知道m(xù)aster還活著。這類事件不會(huì)再binlog或relay log中出現(xiàn)。他們由master的dump事件線程產(chǎn)生,然后直接發(fā)給了slave。slave收到后,校驗(yàn)事件內(nèi)容后,直接拋棄這個(gè)事件,而不會(huì)寫到relay log中。
固定數(shù)據(jù)部分
- 空
可變數(shù)據(jù)部分 - 空