MySQL中binlog有什么用

57次阅读
没有评论

共计 5575 个字符,预计需要花费 14 分钟才能阅读完成。

这篇文章将为大家详细讲解有关 MySQL 中 binlog 有什么用,丸趣 TV 小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

一、binlog 文件和文件的逻辑、物理表现形式
1. binlog 文件

binlog 文件主要包括:

mysql-bin.000001

mysql-bin.index

其中:

mysql-bin.index 内保存着 server 中未 purge 的 binlog 文件,以“文本”形式保留的。

2.binlog 文件格式

mysql-bin.index 没啥可说的,我们专门看一下二进制 binlog 文件。

binlog 文件格式有以下特点:

binlog 是由 event 组成,event 是 binlog 的逻辑最小单元。

文件头的头四个字节为 BINLOG_MAGIC(fe 62 69 6e)

紧接着这四个字节的是 descriptor event:FORMAT_DESCRIPTION_EVENT

文件的末尾是 log-rotation event: ROTATE_EVENT

这两个 event 中间是各种不同的 event,每个 event 代表 Master 上不同的操作。

下面对基本比较关键的概念进行说明:

BINLOG_MAGIC

利用 hexdump -C 读取 mysql-bin.000005 的内容,

这里分别以十六进制和 ASCII 码展示显示,我们可以看到 binlog 的头四个字节是固定的:fe 62 69 6e,后三个字符 ASCII 码为 bin,指明展示一个 binlog 文件。这四个字节成为 BINLOG_MAGIC。

event

mysqlbinlog -vvv 读取 mysql-bin.000011 的内容示例:

这里可以看到,第一个 event 是 FORMAT_DESCRIPTION_EVENT,它记录了这个 binlog 的版本 (MySQL 5.0 以后 binlog 的版本都是 4)。最后一个 event,是 ROTATE_EVENT,它记录了切换到下一个 binlog 文件的文件名。

在它们两个之间是各种其他的 event,目前的 event 类型有:

enum Log_event_type { 
    UNKNOWN_EVENT= 0, 
    START_EVENT_V3= 1, 
    QUERY_EVENT= 2, 
    STOP_EVENT= 3, 
    ROTATE_EVENT= 4, 
    INTVAR_EVENT= 5, 
    LOAD_EVENT= 6, 
    SLAVE_EVENT= 7, 
    CREATE_FILE_EVENT= 8, 
    APPEND_BLOCK_EVENT= 9, 
    EXEC_LOAD_EVENT= 10, 
    DELETE_FILE_EVENT= 11, 
    NEW_LOAD_EVENT= 12, 
    RAND_EVENT= 13, 
    USER_VAR_EVENT= 14, 
    FORMAT_DESCRIPTION_EVENT= 15, 
    XID_EVENT= 16, 
    BEGIN_LOAD_QUERY_EVENT= 17, 
    EXECUTE_LOAD_QUERY_EVENT= 18, 
    TABLE_MAP_EVENT = 19, 
    PRE_GA_WRITE_ROWS_EVENT = 20, 
    PRE_GA_UPDATE_ROWS_EVENT = 21, 
    PRE_GA_DELETE_ROWS_EVENT = 22, 
    WRITE_ROWS_EVENT = 23, 
    UPDATE_ROWS_EVENT = 24, 
    DELETE_ROWS_EVENT = 25, 
    INCIDENT_EVENT= 26, 
    HEARTBEAT_LOG_EVENT= 27, 
    IGNORABLE_LOG_EVENT= 28,
    ROWS_QUERY_LOG_EVENT= 29,
    WRITE_ROWS_EVENT = 30,
    UPDATE_ROWS_EVENT = 31,
    DELETE_ROWS_EVENT = 32,
    GTID_LOG_EVENT= 33,
    ANONYMOUS_GTID_LOG_EVENT= 34,
    PREVIOUS_GTIDS_LOG_EVENT= 35, 
    ENUM_END_EVENT 
    /* end marker */ 
  };
 

当然,内部已经有部分 event 被弃用了,我们不一一列举,这里只简单介绍几个平时经常见到的:

QUERY_EVENT:用于具体的 SQL 文本。如果 binlog_format=statement 方式下,insert,update,delete 等各种 SQL 都是以 Query event 记录下来的。

WRITE_ROWS_EVENT,UPDATE_ROWS_EVENT,DELETE_ROWS_EVENT:在 binlog_format=row 方式下,insert,update,delete 操作的行信息分别以这三种 event 记录下来。

GTID_LOG_EVENT:5.6 的 GTID 模式下,每个事务的 GTID 序号被记录到这种 EVENT 中。

PREVIOUS_GTIDS_LOG_EVENT:5.6 的 GTID 模式下,这个 event 记录了生成这个 binlog 之前,MySQL 已经执行的所有事务的 GTID 集合

二、slave io 在源码中是怎么连上 Master 的

这里主要描述源码中的函数调用关系

1. slave 如何注册并请求 master 的 binlog

slave io 线程对应的入口函数为 sql/rpl_slave.cc:handle_slave_io()

该函数核心主要是做了以下三个事情:

safe_connect(thd, mysql, mi)

register_slave_on_master(mysql, mi, suppress_warnings)

request_dump(thd, mysql, mi, suppress_warnings)

event_len= read_event(mysql, mi, suppress_warnings);

也就是说,它先以标准的连接方式连上 master MySQL,然后把自己注册到 master 上去,接着调用 request_dump 向 master 请求 binlog 数据,最后一个一个 event 读取并存放到本地 relay log 中。

safe_connect

连接 MySQL 的标准方式,MySQL c 的 connector 也是用这种方式连接 MySQL server 的。

register_slave_on_master

slave 把自己的 slave_id,IP,端口,用户名提交给 Master,用于注册自己到 Master 上去。

request_dump

根据 GTID 来进行判断,如果是 GTID 模式,那么把本地执行的 GTID 集合及其他相关信息传给 master;如果不是 GTID 模式,那么就把 master log file 和 Pos 传给主库。主库如何根据这些信息来发送 binlog 的 event,参考下节。

read_event

read_event 调用了 cli_safe_read(),cli_safe_read() 调用了 my_net_read(),等待主库将 binlog 数据发过来

也就是说,read_event 被动的从网络中接受主库发过来的信息。

2. master 如何处理 slave 的 binlog 请求

MySQL 处理各种命令的核心函数为:sql/sql_parse.cc:dispatch_command

该函数会根据用户的请求来确定做什么事情,

COM_REGISTER_SLAVE 则调用 register_slave(thd, (uchar*)packet, packet_length) 注册 slave

COM_BINLOG_DUMP_GTID 则调用 com_binlog_dump_gtid(thd, packet, packet_length);

COM_BINLOG_DUMP 则调用 com_binlog_dump(thd, packet, packet_length);

我们这里以 com_binlog_dump 为例介绍 master 怎么发送 binlog event 给 slave 的。

com_binlog_dump 核心代码为:

kill_zombie_dump_threads(slave_uuid);

mysql_binlog_send(thd, thd- strdup(packet + 10), (my_off_t) pos, NULL)

kill_zombie_dump_threads() 函数:如果新的 server_id 相同的 slave 注册上来,master 会移除跟该 slave 的 server_id 匹配的的 binlog dump 线程

com_binlog_dump() 会调用 mysql_binlog_send() 来打开文件,将文件指针挪到指定位置,读取文件,将一个个的 event 按照事件顺序发给 slave。

综上

MySQL 复制需要 slave 先注册到 Master,再向 Master 提交 binlog 和 POS,请求发送 binlog。Master 接收到请求后,先做一系列验证,打开本地 binlog 文件,按照内部 event 的顺序,依序发给 slave。

三、sql 线程在源码中是怎么读取二进制信息,应用到本地 MySQL 的

sql 线程在 5.6 引入了 db 级别的并行,所以有两个入口

1

2

handle_slave_worker

 handle_slave_sql

handle_slave_worker 线程是主要干活的函数,handle_salve_sql 函数作为协调器会启动和分配 worker 线程。

handle_slave_sql 函数主要调用了 slave_worker_exec_job。

slave_worker_exec_job 的主要功能:

job_item= pop_jobs_item(worker, job_item); ev= static_cast Log_event* (job_item- data);

error= ev- do_apply_event_worker(worker);

该函数做到事情其实就是 从 handle_salve_sql() 获得具体的 event(ev),然后调用 ev- do_apply_event_worker(worker),利用 c ++ 的多态特性,调用真正的 event 的 do_apply_event 虚函数,以便将不同的 event 的操作在本地做一遍。

这里需要大家回顾一下 event 的概念了,event 是 binlog 的最小单元,所有的 event 的父类是 Log_event(抽象基类),它定义了一系列虚函数,其中就包括我们这里调用的函数:

这里举一个 insert 语句对应的的 Write_rows_log_event 例子,简单说明一下数据是怎么应用到本地 MySQL 的。

Write_rows_log_event,Update_rows_log_event 和 Delete_rows_log_event 的 do_apply_event 都是调用的它的基类 Rows_log_event 的 do_apply_event。

Rows_log_event 的 do_apply_event 主要功能如下:

m_table= const_cast relay_log_info* >

error= (this- *do_apply_row_ptr)(rli);

get_table() 先从 table map 中获得对应的 table 的信息,然后调用 do_apply_row_ptr 函数指针指向的函数来将 event 对应操作应用到本地 MySQL。

do_apply_row_ptr 函数指针可能指向以下几种不同的函数:

do_hash_scan_and_update

do_index_scan_and_update

do_table_scan_and_update

do_apply_row

Write_rows_log_event 是 insert,不用查找数据,所以它调用的是 do_apply_row。

do_apply_row 主要的功能就是调用了 do_exec_row …. 汗

do_exec_row 是 Write_rows_log_event 自己实现的,它的主要功能是调用了 write_row …. 汗

write_row 也是 Write_rows_log_event 自己实现的,它的主要功能是:m_table- file- ha_start_bulk_insert(estimated_rows); 也就是说,它直接把这一行数据交给了存储引擎,让存储引擎把数据给插进去。

四、binlog_format=ROW 格式下,MySQL 是怎么用二进制保存各种不同的数据类型的

在 sql/log_event.cc:log_event_print_value() 函数中详细描述了 MySQL 的各种数据类型的二进制表现形式,摘录如下

这里有几个比较有意思的地方:

MYSQL_TYPE_STRING 类型,它的 length 占用的字节数是不固定的。如果 string 长度不到大于 255,则需要占用 2 个字节,所以,MySQL 在定义 String 类型的字段时,255 是一个坎,如果字段不可能超过 255 个字节,不建议定义长度的时候超过 255,否则 MySQL 存储数据时会白白浪费一个字节。

MYSQL_TYPE_DATETIME 类型。它存储的格式就是把年 - 月 - 日 时:分:秒按顺序存储下来的,比如:2015-10-10 22:45:55 存储下来就存储为 20151010224545。这种存储格式比较浪费,所以字节数相比 timestamp 占用的也比较多。

关于“MySQL 中 binlog 有什么用”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-27发表,共计5575字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)