首页 > 数据库 > MySQL > MySQL binlog相关源码浅析
整理的内容主要针对以下四个问题:
binlog文件主要包括:
其中:
mysql-bin.index内保存着server中未purge的binlog文件,以“文本”形式保留的。
mysql-bin.index没啥可说的,我们专门看一下二进制binlog文件。
binlog文件格式有以下特点:
下面对基本比较关键的概念进行说明:
利用hexdump -C 读取mysql-bin.000005的内容,
这里分别以十六进制和ASCII码展示显示,我们可以看到binlog的头四个字节是固定的:fe 62 69 6e,后三个字符ASCII码为bin,指明展示一个binlog文件。这四个字节成为 BINLOG_MAGIC。
mysqlbinlog -vvv 读取mysql-bin.000011的内容示例:
这里可以看到,第一个event是FORMAT_DESCRIPTION_EVENT,它记录了这个binlog的版本(MySQL 5.0以后binlog 的版本都是4)。最后一个event,是ROTATE_EVENT,它记录了切换到下一个binlog文件的文件名。
在它们两个之间是各种其他的event,目前的event类型有:
当然,内部已经有部分event被弃用了,我们不一一列举,这里只简单介绍几个平时经常见到的:
这里主要描述源码中的函数调用关系
slave io线程对应的入口函数为sql/rpl_slave.cc:handle_slave_io()
该函数核心主要是做了以下三个事情:
也就是说,它先以标准的连接方式连上master MySQL,然后把自己注册到master上去,接着调用request_dump向master请求binlog数据,最后一个一个event读取并存放到本地relay log中。
连接MySQL的标准方式,MySQL c的connector也是用这种方式连接MySQL server的。
根据GTID来进行判断,如果是GTID模式,那么把本地执行的GTID集合及其他相关信息传给master;如果不是GTID模式,那么就把master log file和Pos传给主库。主库如何根据这些信息来发送binlog的event,参考下节。
read_event调用了cli_safe_read(),cli_safe_read()调用了my_net_read(),等待主库将binlog数据发过来
也就是说,read_event被动的从网络中接受主库发过来的信息。
MySQL处理各种命令的核心函数为:sql/sql_parse.cc:dispatch_command
该函数会根据用户的请求来确定做什么事情,
我们这里以com_binlog_dump为例介绍master怎么发送binlog event给slave的。
com_binlog_dump核心代码为:
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线程在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的主要功能:
该函数做到事情其实就是 从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主要功能如下:
get_table()先从table map中获得对应的table的信息,然后调用do_apply_row_ptr函数指针指向的函数来将event对应操作应用到本地MySQL。
do_apply_row_ptr函数指针可能指向以下几种不同的函数:
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);也就是说,它直接把这一行数据交给了存储引擎,让存储引擎把数据给插进去。
在sql/log_event.cc:log_event_print_value()函数中详细描述了MySQL的各种数据类型的二进制表现形式,摘录如下
这里有几个比较有意思的地方:
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/26250550/viewspace-1979601/ ,如需转载,请注明出处,否则将追究法律责任。