Binlog

什么是 Binlog

MySQL Server有四种类型的日志——Error LogGeneral Query LogBinary LogSlow Query Log

  第一个是错误日志,记录 mysqld (mysql daemon)的一些错误。第二个是一般查询日志,记录 mysqld 正在做的事情,比如客户端的连接和断开、来自客户端每条 Sql Statement 记录信息;如果你想知道客户端到底传了什么给服务端,这个日志就非常管用了,不过它非常影响性能。第四个是慢查询日志,记录一些查询比较慢的 SQL 语句——这种日志非常常用,主要是给开发者调优用的。

  第三种就是 Binlog 了,binlog是mysql的二进制日志,包含了一些事件,这些事件描述了数据库的改动,如建表、数据改动等,也包括一些潜在改动,比如 DELETE FROM ran WHERE bing = luan,然而一条数据都没被删掉的这种情况。除非使用 Row-based logging,否则会包含所有改动数据的 SQL Statement

注意:binlog主要有statement-basedrow-based loggingmixed logging 三种格式,row-based的记录中不包括潜在更新记录。

   Binlog 有两个重要的用途——复制和恢复。比如主从表的复制,和备份恢复。

注:mysqldMySQL服务器的守护进程。

binlog格式

可以指定三种binary log的格式(启动时指定):

1
2
3
--binlog-format=STATEMENT
--binlog-format=ROW
--binlog-format=MIXED
  • statement-based logging: 基于SQL语句,Mysql5.6默认,某些语句和函数如UUID, LOAD DATA INFILE等在复制过程可能导致数据不一致甚至出错。
  • row-based logging:基于行,记录影响table中每一行的事务,很安全。所以一条语句可能会对应0-N个事件,记录很详细,数据同步的支持比STATEMENT方式要好。但是binlog会比其他两种模式大很多,在一些大表中清除大量数据时在binlog中会生成很多条语句,可能导致从库延迟变大。
  • mixed logging:使用statement-based logging作为默认,但是日志模式可能会在某些情况下自动切换到row-based logging

启用 Binlog

通常情况 MySQL 是默认关闭 Binlog 的,需要在my.cnf中手动配置启用它。

1
2
3
4
5
6
# log-bin 是指以后生成各 Binlog 文件的前缀,比如上述使用 master-bin,那么文件就将会是
# master-bin.000001、master-bin.000002 等
log-bin=master-bin
# log-bin-index 则指 binlog index 文件的名称,这里我们设置为 master-bin.index。
log-bin-index=master-bin.index

启动MySQL服务

1
2
3
# mysqld_safe是一个启动脚本,该脚本会调用mysqld启动,如果启动出错,会将错误信息记录到错误日志中
$ ./mysqld_safe &
# 符号“&”表示在后台启动

启动MySQL客户端

1
$ mysql -u $USERNAME -p $PASSWORD

在客户端终端里面输入下面一句 SQL语句:

1
$ SHOW VARIABLES LIKE '%log_bin%';

显示结果如下:

1
2
3
4
5
6
7
8
9
10
11
+---------------------------------+---------------------------------------+
| Variable_name | Value |
+---------------------------------+---------------------------------------+
| log_bin | ON |
| log_bin_basename | /usr/local/var/mysql/master-bin |
| log_bin_index | /usr/local/var/mysql/master-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+---------------------------------------+
6 rows in set (0.00 sec)

结构解析

索引文件

  索引文件就是 master-bin.index 文件,是一个普通的文本文件,以换行为间隔,一行一个文件名。比如它可能是:

1
2
3
master-bin.000001
master-bin.000002
master-bin.000003

  然后对应的每行文件就是一个 Binlog实体文件了。

Binlog 文件

  Binlog 的文件结构大致由如下几个方面组成。

文件头

  文件头由一个四字节 Magic Number,其值为 1852400382,在内存中就是 "\xfe\x62\x69\x6e".

  与平常二进制一样,通常都有一个 Magic Number 进行文件识别,如果 Magic Number不吻合上述的值那么这个文件就不是一个正常的 Binlog

事件

  在文件头之后,跟随的是一个个事件依次排列。每个事件都由一个事件头和事件体组成。

  事件头里面的内容包含了这个事件的类型(如新增、删除等)、事件执行时间以及是哪个服务器执行的事件等信息。

  第一个事件是一个事件描述符,描述了这个 Binlog 文件格式的版本。接下去的一堆事件将会按照第一个事件描述符所描述的结构版本进行解读。最后一个事件是一个衔接事件,指定了下一个 Binlog 文件名——有点类似于链表里面的 next 指针。

事件头

  一个事件头有 19 字节,依次排列为四字节的时间戳、一字节的当前事件类型、四字节的服务端 ID、四字节的当前事件长度描述、四字节的下个事件位置(方便跳转)以及两字节的标识。

Header的格式如下:

1
2
3
|---------|---------|--------|-----------|----------------------|-----|
| 4byte | 1byte | 4byte | 4byte | 4byte |2byte|
|timestamp|EventType|serverId|data-length|nextEventStartPosition|flag |
事件体

  事实上在 Binlog 事件中应该是有三个部分组成,headerpost-headerpayload,不过通常情况下我们把 post-headerpayload 都归结为事件体,实际上这个 post-header 里面放的是一些定长的数据.

实际上一个真正的事件体由两部分组成:

1
2
3
4
5
+=====================================+
| event | fixed part (post-header) |
| data +----------------------------+
| | variable part (payload) |
+=====================================+

而这个 post-header 对于不同类型的事件来说长度是不一样的,同种类型来说是一样的,而这个长度的预先规定将会在一个“格式描述事件”中定好。

标识更新操作

1
2
3
4
|------------------post-header------------------|--------payload------ --|
|--------|-------------|-------------|----------|-------|---------------|--------|
| 4byte | 4byte | 1byte | 2byte | 2byte | nbyte | nbyte |
|ThreadId|ExecutionTime|DbNameLength |error code| status| database | Sql |

标识写入操作

1
2
3
4
|---post-header--|---------payload------------|
|-------|--------|---- --|--- ---|------------|
| 6byte | 2byte | byte | nbyte | nbyte |
|tableId|Reserved|col_num|map_col|insert_value|

col_num: 代表字段的个数占用字节数是可变的,一般一字节就够了,1字节/2的八次方 一般也很难有表有几百个字段

map_col: 这个代表字段是否为空,每一位映射一个列,描述是否被使用, N列的对应的size=int((N+7)/8)bytes

insert_value:这个就是具体的记录内容。

标识binlog文件结束,以及新的binlog文件的名称和位置

1
2
3
4
|---post-header--|-----payload-----|
|----------------|-----------------|
| 8byte | nbyte |
| BinlogPosition | BinlogFilename |
格式描述事件

​ 在 Magic Number 之后跟着的是一个格式描述事件,其实这只是在 v4 版本中的称呼,在以前的版本里面叫起始事件。

  • v1,用于 MySQL 3.2.3
  • v3,用于 MySQL 4.0.2 以及 4.1.0
  • v4,用于 MySQL 5.0 以及更高版本

在 v4 版本中这个事件的结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
+=====================================+
| event | timestamp 0 : 4 |
| header +----------------------------+
| | type_code 4 : 1 | = FORMAT_DESCRIPTION_EVENT = 15
| +----------------------------+
| | server_id 5 : 4 |
| +----------------------------+
| | event_length 9 : 4 | >= 91
| +----------------------------+
| | next_position 13 : 4 |
| +----------------------------+
| | flags 17 : 2 |
+=====================================+
| event | binlog_version 19 : 2 | = 4
| data +----------------------------+
| | server_version 21 : 50 |
| +----------------------------+
| | create_timestamp 71 : 4 |
| +----------------------------+
| | header_length 75 : 1 |
| +----------------------------+
| | post-header 76 : n | = array of n bytes, one byte per event
| | lengths for all | type that the server knows about
| | event types |
+=====================================+

 这个事件的 type_code 是 15,然后 event_length 是大于等于 91 的值的,这个主要取决于所有事件类型数。

  因为从第 76 字节开始后面的二进制就代表一个字节类型的数组了,一个字节代表一个事件类型的 post-header 长度,即每个事件类型固定数据的长度。

校验和

​ 从5.6开始,如果服务器设置产生检验和的前提,事件末尾就多一个检验和字段,是一个32位整型数,用来检查时间写入后是否有损坏

参考

mysql的binlog初探

启动服务并登录MySQL数据库

Linux系统下MySQL的启动方式

binlog 事件体

binlog 结构详解

热评文章