什么是Binlog?浅析MySQL中的Binlog
来源:SegmentFault
时间:2023-02-24 13:41:38 475浏览 收藏
小伙伴们有没有觉得学习数据库很有意思?有意思就对了!今天就给大家带来《什么是Binlog?浅析MySQL中的Binlog》,以下内容将会涉及到MySQL、binlog,若是在学习中对其中部分知识点有疑问,或许看了本文就能帮到你!
花瓣网的搜索架构需要重构,尤其是在索引建立或者更新层面。
目前的一个架构导致的结果就是时间越久,数据本体与搜索引擎索引中的数据越不同步,相差甚大。
新的一个架构打算从 MySQL 的 Binlog 中读取数据更新、删除、新增等历史记录,并把相应信息提取出来丢到队列中慢慢去同步。
所以我就在这里小小去了解一下 Binlog。
准备工作
什么是 Binlog
MySQL Server 有四种类型的日志——Error Log、General Query Log、Binary Log 和 Slow Query Log。
第一个是错误日志,记录 mysqld 的一些错误。第二个是一般查询日志,记录 mysqld 正在做的事情,比如客户端的连接和断开、来自客户端每条 Sql Statement 记录信息;如果你想准确知道客户端到底传了什么瞎 [哔哔] 玩意儿给服务端,这个日志就非常管用了,不过它非常影响性能。第四个是慢查询日志,记录一些查询比较慢的 SQL 语句——这种日志非常常用,主要是给开发者调优用的。
剩下的第三种就是 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、四字节的当前事件长度描述、四字节的下个事件位置(方便跳转)以及两字节的标识。
用 ASCII Diagram 表示如下:
+---------+---------+---------+------------+-------------+-------+ |timestamp|type code|server_id|event_length|next_position|flags | |4 bytes |1 byte |4 bytes |4 bytes |4 bytes |2 bytes| +---------+---------+---------+------------+-------------+-------+
也可以字节编造一个结构体来解读这个头:
cstruct BinlogEventHeader
{
int timestamp;
char type_code;
int server_id;
int event_length;
int next_position;
char flags[2];
};
如果你要直接用这个结构体来读取数据的话,需要加点手脚。
因为默认情况下 GCC 或者 G++ 编译器会对结构体进行字节对齐,这样读进来的数据就不对了,因为 Binlog 并不是对齐的。为了统一我们需要取消这个结构体的字节对齐,一个方法是使用
#pragma pack(n),一个方法是使用__attribute__((__packed__)),还有一种情况是在编译器编译的时候强制把所有的结构体对其取消,即在编译的时候使用fpack-struct参数,如:```sh
$ g++ temp.cpp -o a -fpack-struct=1
<br> 根据上述的结构我们可以明确得到各变量在结构体里面的偏移量,所以在 MySQL 源码里面([libbinlogevents/include/binlog_event.h](https://github.com/mysql/mysql-server/blob/5.7/libbinlogevents/include/binlog_event.h#L353))有下面几个常量以快速标记偏移: ```c #define EVENT_TYPE_OFFSET 4 #define SERVER_ID_OFFSET 5 #define EVENT_LEN_OFFSET 9 #define LOG_POS_OFFSET 13 #define FLAGS_OFFSET 17
而具体有哪些事件则在 libbinlogevents/include/binlog_event.h#L245 里面被定义。如有个
FORMAT_DESCRIPTION_EVENT事件的
type_code是 15、
UPDATE_ROWS_EVENT的
type_code是 31。
还有那个
next_position,在 v4 版本中代表从 Binlog 一开始到下一个事件开始的偏移量,比如到第一个事件的
next_position就是 4,因为文件头有一个字节的长度。然后接下去对于事件 n 和事件 n + 1 来说,他们有这样的关系:
next_position(n + 1) = next_position(n) + event_length(n)
关于 flags 暂时不需要了解太多,如果真的想了解的话可以看看 MySQL 的相关官方文档。
事件体
事实上在 Binlog 事件中应该是有三个部分组成,
header、
post-header和
payload,不过通常情况下我们把
post-header和
payload都归结为事件体,实际上这个
post-header里面放的是一些定长的数据,只不过有时候我们不需要特别地关心。想要深入了解可以去查看 MySQL 的官方文档。
所以实际上一个真正的事件体由两部分组成,用 ASCII Diagram 表示就像这样:
+=====================================+ | event | fixed part (post-header) | | data +----------------------------+ | | variable part (payload) | +=====================================+
而这个
post-header对于不同类型的事件来说长度是不一样的,同种类型来说是一样的,而这个长度的预先规定将会在一个“格式描述事件”中定好。
格式描述事件
在上文我们有提到过,在 Magic Number 之后跟着的是一个格式描述事件(Format Description Event),其实这只是在 v4 版本中的称呼,在以前的版本里面叫起始事件(Start Event)。
在 v4 版本中这个事件的结构如下面的 ASCII Diagram 所示。
+=====================================+ | 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长度,即每个事件类型固定数据的长度。
那么按照上述的一些线索来看,我们能非常快地写出一个简单的解读 Binlog 格式描述事件的代码。
如上文所述,如果需要正常解读 Binlog 文件的话,下面的代码编译时候需要加上
-fpack-struct=1这个参数。
cpp
#include <cstdio>
#include <cstdlib>
struct BinlogEventHeader
{
int timestamp;
unsigned char type_code;
int server_id;
int event_length;
int next_position;
short flags;
};
int main()
{
FILE* fp = fopen("/usr/local/var/mysql/master-bin.000001", "rb");
int magic_number;
fread(&magic_number, 4, 1, fp);
printf("%d - %sn", magic_number, (char*)(&magic_number));
struct BinlogEventHeader format_description_event_header;
fread(&format_description_event_header, 19, 1, fp);
printf("BinlogEventHeadern{n");
printf(" timestamp: %dn", format_description_event_header.timestamp);
printf(" type_code: %dn", format_description_event_header.type_code);
printf(" server_id: %dn", format_description_event_header.server_id);
printf(" event_length: %dn", format_description_event_header.event_length);
printf(" next_position: %dn", format_description_event_header.next_position);
printf(" flags[]: %dn}n", format_description_event_header.flags);
short binlog_version;
fread(&binlog_version, 2, 1, fp);
printf("binlog_version: %dn", binlog_version);
char server_version[51];
fread(server_version, 50, 1, fp);
server_version[50] = '</cstdlib></cstdio> -
499 收藏
-
244 收藏
-
235 收藏
-
157 收藏
-
101 收藏
-
460 收藏
-
349 收藏
-
223 收藏
-
406 收藏
-
486 收藏
-
294 收藏
-
117 收藏
-
411 收藏
-
420 收藏
-
264 收藏
-
266 收藏
-
392 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习