mysql io_mysql主从复制io线程源码分析

mysql主从复制通过binlog来同步数据,在从库上执行start slave,会开启两个线程,分别是io线程和sql线程。io线程负责从主库拉取binlog并存储到本地的relay log,sql线程负责把relay log中的事务在从库应用。本文将结合源码(5.7.19版本)讨论io线程的具体实现。

io线程函数:

mysql io线程函数在源码sql/rpl_slave.cc中实现,执行命令start slave或者start slave io_thread,就会创建io线程,io线程函数为:extern "C" void *handle_slave_io(void *arg)。

io线程函数的参数arg,实际上是一个Master_info类型的指针mi,保存了主库相关的一些信息,比如host,user,password,主库uuid,主库binlog文件名,主库binlog文件位置等等。

io线程函数中会创建一个THD的对象,一个THD的对象就相当于一个连接,这个连接是可以在show processlist中看到,实际上io线程也可以理解为一个通向主库的连接。

紧接着io线程函数初始化一个MYSQL结构体的指针,称之为mysql,主要作用是与主库通信,走的标准的MySQL客户端/服务器协议,后面io线程获取主库的信息,注册从库,拉取binlog,都将依赖这个指针。

创建连接:

有了mi和mysql,通过调用函数safe_connect(thd, mysql, mi),连接到主库。

交换信息:

调用get_master_version_and_clock(mysql, mi),获取主库的版本,时间,server_id,字符集校验规则,时区等等信息,如果发现主库的server_id与从库的server_id相同,则会报错。

调用get_master_uuid(mysql, mi),获取主库的server_uuid,如果主库的server_uuid与从库的server_uuid相同,也会报错。

调用io_thread_init_commands(mysql, mi),把从库的server_uuid作为session变量设置到连接上,发送给主库。

注册从库:

调用 register_slave_on_master(mysql, mi, &suppress_warnings),在主库上注册从库,注册过程实际上就是发送一个注册命令COM_REGISTER_SLAVE,以及一个特定结构的网络包到主库。这个包结构如下:

从库server_id,4字节从库report_host,如果为空,占用1个字节,值为0从库report_user,如果为空,占用1个字节,值为0从库report_password,如果为空,占用1个字节,值为0从库report_port,2字节rpl_recovery_rank,4字节,默认为0,兼容老版本master_id,4字节,值为0,由主库来填充通过抓包,可以清楚地看到包内容与上述结构完全吻合。下图c304f30a是从库的server_id,000000为report_host,report_user,report_password。ea0c为report_port,后面8字节分别为rpl_recovery_rank,master_id。

22ca611e340192da5bea9115f0d8fc71.png

拉取binlog:

调用request_dump(thd, mysql, mi, &suppress_warnings),向主库发送binlog拉取的命令。如果开启GTID,命令为COM_BINLOG_DUMP_GTID,如果没有开启GTID,命令为COM_BINLOG_DUMP。

请求拉取binlog的网络包结构为:

binlog_flags,2字节从库server_id,4字节binlog名称的大小,4字节binlog名称,占用字节由3决定binlog位置,4字节binlog数据大小,4字节gtid_executed,大小待定开启GTID之后,binlog文件名和binlog位置这两个参数都是固定值,binlog文件名全为0,binlog位置为4,gtid_executed才是真正起作用的。

读取binlog:

请求拉取binlog的命令发送完成之后,io线程在一个while循环中,不断调用read_event(mysql, mi, &suppress_warnings) 来读取主库发送的binlog数据,并写入到relay log文件中。

总结:

至此io线程的整体逻辑就完成了,从上述过程来看,io线程连接到主库,与主库交换一些必要的信息,在主库上注册从库,然后请求拉取binlog,最后循环调用read_event,将主库不断发送的binlog信息写入到relay log文件中。整个过程很简单,但是需要考虑的细节有很多。了解io线程的主要流程,我们甚至可以自己写一个程序,模拟io线程,从主库拉取binlog。当然前提是需要了解MySQL的client/server的协议,或者使用现成的mysql开发库。

附录:

io线程函数handle_slave_io定义:sql/rpl_slave.cc

Master_info类定义:sql/rpl_mi.h

MYSQL结构体定义:include/mysql.h

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值