上次,我們僅僅把binlog做了一個概述,並沒有去深入探索(1)binlog file究竟是怎麼構成的?(2)binlog file的單元binlog events是怎麼構成的?(3)我們能不能偽造出一個mysqlbinlog識別的binlog file? 當然,第三個問題看起來很cool,蠻有挑戰 ...
上次,我們僅僅把binlog做了一個概述,並沒有去深入探索(1)binlog file究竟是怎麼構成的?(2)binlog file的單元binlog events是怎麼構成的?(3)我們能不能偽造出一個mysqlbinlog識別的binlog file? 當然,第三個問題看起來很cool,蠻有挑戰性的。
這次我們討論的是第4版本的binlogfile, 一般5.0.x以上的mysql使用該版本的binlogfile。
首先回答第一個問題
一、binlog file的構成
(1)binlog file的大致構成
這個問題其實之前也回答過,但是很不深入。這次,我會深度探索它,首先我們扒一扒官方的說法;
http://dev.mysql.com/doc/internals/en/binlog-file.html
這塊就說了一句話:binlog file是由binlog file header和binlog events構成的,至於binlog file header其實就是0xfe62696e。換言之,binlog file先寫了個0xfe62696e,然後後面跟著許多binlog event 。官方的文檔還是很給力的,我們可以打開任意一個binlog file,以16進位形式打開,開頭就是0xfe62696e。
(2)binlog events的組織方式
許多binlog event是否存在著自己的組織方式呢?答案是肯定的,跟在binlog file header後面的一般先是Binlog::FORMAT_DESCRIPTION_EVENT,這是第4版本的binlog event的開頭,這個會在本文的"二、binlog events的構成"中詳細提到。
緊接著一般是事務性的binlog events,要強調的是,在binlog file里所有的update, delete, insert語句都是存在於一組事務性的binlog event。
事務性的binlog events的格式如下(SQL代表任一SQL語句,當然一般只包含select,update, delete, insert語句,不包括ddl語句):
sql語句形式 | statement格式 | row格式 |
/ | Anonymous_gtid_event | Anonymous_gtid_event |
BEGIN | Query_event(BEGIN) | Query_event(BEGIN) |
SQL | Query_event(SQL) | Table_map_event & Rows_event |
SQL | Query_event(SQL) | Table_map_event & Rows_event |
...... | ...... | ...... |
COMMIT | Xid_event | Xid_event |
至於mixed格式就是statement格式 和row格式交替出現,三種格式的不同也就在這個上面,至於上面看到的binlog events的格式,我們將在本文的"二、binlog events的構成"中詳細提到。
最後會以STOP_EVENT或者ROTATE_EVENT結尾,這兩個也會在本文的"二、binlog events的構成"中詳細提到。
其他的一些binlog event不是特別重要,有興趣的可以通過
http://dev.mysql.com/doc/internals/en/binlog-event.html去瞭解
二、binlog event的構成
(1)binlog event的構成
binlog event分為四部分:common header, post header, body以及footor,翻譯能力有限,不知道怎麼翻譯,但是只要明白就好,common header和footor是共有的,而post header, body則是每個event都獨有的。
common header 一般包含下麵幾個
名稱 | 格式 | 描述 |
when | 4位元組整形 | 事件發生的時間,從1970年開始到現在的秒數 |
type_code | 1位元組整形 | binglog event的類型 |
unmasked_server_id | 4位元組整形 | 伺服器id |
data_written | 4位元組整形 | binglog event的長度,即common header的長度 + post header的長度 + body的長度+4 |
log_pos | 4位元組整形 | 下一個binglog event在文件中的位置 |
flags | 2位元組整形 | binglog 的版本號 |
footor則包含一個crc32校驗碼,它的格式是4位元組的整形。
(2)重要的binlog event的構成
1)FORMAT_DESCRIPTION_EVENT
參考自http://dev.mysql.com/doc/internals/en/format-description-event.html
body:
名稱 | 格式 | 描述 |
binlog-version | 2位元組整形 | binlog的版本,一般為4 |
mysql-server version | 50位元組字元串 | mysql資料庫的版本 |
create timestamp | 4位元組整形 | 創建時間 |
event header length | 1位元組整形 | common header的長度,一般為19 |
event type header lengths | EOF型字元串 | 各種binlog event的post header的長度 |
2)Xid_event
參考自http://dev.mysql.com/doc/internals/en/xid-event.html
body:
名稱 | 格式 | 描述 |
XID | 8位元組整形 | 提交的事務id |
3) Anonymous_gtid_event
沒有可以參考的網站
post header:
名稱 | 格式 | 描述 |
commit flag | 1位元組整形 | 是否提交,1代表提交,0代表沒有提交 |
ENCODED SID | 16位元組整形 | 一般為0 |
ENCODED GNO | 8位元組整形 | 一般為0 |
TS_TYPE | 1位元組整形 | 一般為2 |
body:
名稱 | 格式 | 描述 |
last_committed | 8位元組整形 | 上一次提交的序列號 |
sequence_number | 8位元組整形 | 本次的序列號 |
4)STOP_EVENT
參考自http://dev.mysql.com/doc/internals/en/stop-event.html
沒有post header和body
5)ROTATE_EVENT
參考自http://dev.mysql.com/doc/internals/en/rotate-event.html
post header:
名稱 | 格式 | 描述 |
position | 8位元組整形 | 下一個binlog event的位置 |
body:
名稱 | 格式 | 描述 |
name of the next binlog | 字元串 | 下一個binlog event所在的文件名 |
6)Table_map_event
參考自http://dev.mysql.com/doc/internals/en/table-map-event.html
post header
名稱 | 格式 | 描述 |
table id | 4位元組整形 | 表id,在mysql資料庫中每個表都有一個唯一的id標識 |
flgas | 2位元組整形 | 當前保留,為以後使用 |
body:
名稱 | 格式 | 描述 |
schema name length | 1位元組整形 | 資料庫名長度 |
schema name | NULL字元串 | 資料庫名 |
table name length | 1位元組整形 | 表名長度 |
table name | NULL字元串 | 表名 |
column-count | 可變的整形 | 列數量 |
column-def | 字元串 | 描述每列的數據類型 |
column-meta-def | 字元串 | 描述每列的元數據 |
NULL-bitmask | 字元串 | 描述每列的是不是可以為空 |
7)ROWS_EVENT
參考自http://dev.mysql.com/doc/internals/en/rows-event.html
post header
名稱 | 格式 | 描述 |
table id | 4位元組整形 | 表id,在mysql資料庫中每個表都有一個唯一的id標識 |
flgas | 2位元組整形 | 當前保留,為以後使用 |
body
名稱 | 格式 | 描述 |
var_header_len | 4位元組整形 | 表的列數 |
columns_before_image | 字元串 | 被使用列的比特值,例如,表有3列,只有第1列和第3列被使用,則該值為0xfa,只有第1列和第2列被使用,則該值為0xfc |
columns_after_image | 字元串 | 僅用於update命令,即更新後的情況是在這裡獲取的,delete和insert都沒有該項 |
row | 字元串 |
string.var_len nul-bitmap, length (bits set in 'columns-present-bitmap1'+7)/8 |
8) QUERY_EVENT
參考自http://dev.mysql.com/doc/internals/en/query-event.html
post header
名稱 | 格式 | 描述 |
slave_proxy_id | 4位元組整形 | 從機代理id |
execution time | 4位元組整形 | 執行時間 |
schema length | 1位元組整形 | 資料庫名長度 |
error-code | 2位元組整形 | 錯誤碼 |
status-vars length | 2位元組整形 | 狀態長度 |
body
名稱 | 格式 | 描述 |
status-vars | 字元串 | 執行sql語句的mysql的環境變數 |
schema | NULL字元串 | 資料庫名 |
query | EOF字元串 | SQL語句 |
三、偽造的binlog文件
現在通過上面的介紹,我們已經能偽造我們的binlog文件,只不過我們只能偽造statement格式下的binlog,因為row模式下的binlog是需要sql執行時的真實數據的。