上次,我们仅仅把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 string.var_len value of each field as defined in table-map 这里的包含每一个行,每一行含有 nul-bitmap代表已使用的列是否为null,然后紧接着是数据value of each field as defined in table-map
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执行时的真实数据的。