初探 MySQL 的 Binlog
发布在数据库之撸2015年8月10日view:1281
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

原文地址:https://xcoder.in/2015/08/10/mysql-binlog-try/

  花瓣网的搜索架构需要重构,尤其是在索引建立或者更新层面。

  目前的一个架构导致的结果就是时间越久,数据本体与搜索引擎索引中的数据越不同步,相差甚大。

  新的一个架构打算从 MySQL 的 Binlog 中读取数据更新、删除、新增等历史记录,并把相应信息提取出来丢到队列中慢慢去同步。

  所以我就在这里小小去了解一下 Binlog。

准备工作

什么是 Binlog

  MySQL Server 有四种类型的日志——Error Log、General Query Log、Binary Log 和 Slow Query Log。

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

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

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

启用 Binlog

  通常情况 MySQL 是默认关闭 Binlog 的,所以你得配置一下以启用它。

  启用的过程就是修改配置文件 my.cnf 了。

  至于 my.cnf 位置请自行寻找。例如通过 OSX 的 brew 安装的 mysql 默认配置目录通常在

/usr/local/Cellar/mysql/$VERSION/support-files/my-default.cnf

  这个时候需要将它拷贝到 /etc/my.cnf 下面。

详见 <StackOverflow - MySQL ‘my.cnf’ location?>。

  紧接着配置 log-binlog-bin-index 的值,如果没有则自行加上去。

log-bin=master-bin
log-bin-index=master-bin.index

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

  如果上述工作做完之后重启 MySQL 服务,你可以进入你的 MySQL CLI 验证一下是否真的启用了。

$ mysql -u $USERNAME ...

  然后在终端里面输入下面一句 SQL 语句:

SHOW VARIABLES LIKE '%log_bin%';

  如果结果里面出来这样类似的话就表示成功了:

+---------------------------------+---------------------------------------+
| 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)

  更多的一些相关配置可以参考这篇《MySQL 的 binary log 初探》。

随便玩玩

  然后你就可以随便去执行一些数据变动的 SQL 语句了。当你执行了一堆语句之后就可以看到你的 Binlog 里面有内容了。

  如上表所示,log_bin_basename 的值是 /usr/local/var/mysql/master-bin 就是 Binlog 的基础文件名了。

  那我们进去看,比如我的这边就有这么几个文件:

Binlog 文件

  很容易发现,里面有 master-bin.indexmaster-bin.000001 两个文件,这两个文件在上文中有提到过了。

  我们打开那个 master-bin.index 文件,会发现这个索引文件就是一个普通的文本文件,然后列举了各 binlog 的文件名。而 master-bin.000001 文件就是一堆乱码了——毕竟人家是二进制文件。

结构解析

索引文件

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

master-bin.000001
master-bin.000002
master-bin.000003

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

Binlog 文件

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

文件头

  文件头由一个四字节 Magic Number,其值为 1852400382,在内存中就是 "\xfe\x62\x69\x6e",参考 MySQL 源码的 log_event.h,也就是 '\0xfe' 'b' 'i' 'n'

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

事件

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

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

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

  根据《[High-Level Binary Log Structure and Contents](High-Level Binary Log Structure and Contents)》所述,不同版本的 Binlog 格式不一定一样,所以也没有一个定性。在我写这篇文章的时候,目前有三种版本的格式。

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

      实际上还有一个 v2 版本,不过只在早期 4.0.x 的 MySQL 版本中使用过,但是 v2 已经过于陈旧并且不再被 MySQL 官方支持了。

通常我们现在用的 MySQL 都是在 5.0 以上的了,所以就略过 v1 ~ v3 版本的 Binlog,如果需要了解 v1 ~ v3 版本的 Binlog 可以自行前往上述的《High-level…》文章查看。

事件头

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