深入了解MySQL replication
1. 简介
本文主要讲解MySQL的replication协议的过程和如何通过伪造客户端与Server通信,获取Binlog日志以及部分重点日志的解析,并对比了不同Binlog类型的优缺点
2. Replication过程
2.1 复制方案
- MySQL的Master主服务器将数据的改动记录到本地的Binlog中
- MySQL的Slave从服务器中的I/O线程将MySQL Master的Binlog同步到本地,保存在Replay Log中继日志中
- MySQL的Slave从服务器中的SQL线程读取中继日志,将数据的变化同步到本身
2.2 Binlog类型
2.2.1 Row
Master将详细记录表中的每一行数据的变化情况到Binlog中。
优点:完整的记录了每一行数据的变化情况,以及每一行数据中各个属性列的信息,因此不会出现因为依赖上下文信息导致主从数据不一致的问题
缺点:每一行数据的操作都会完整的记录在binlog中,并且伴随每一次操作事件都会有table_map事件,消耗大量的存储空间
2.2.2 Statement
将每一条修改数据的SQL都记录到Binlog中
优点:不需要记录每行数据的变化,节省了存储的I/O,性能较高。
缺点:可能会因为缺少上下文的信息导致数据不一致
2.2.3 Mixed
将以上两种模式融合,根据SQL语句自动选择Row和Statement模式
优点:在数据的一致性、性能和存储空间上做到很好的平衡
缺点:解析处理较麻烦
2.3 协议
MySQL replication协议相对简单,client向Server发送一个MySQL binlog dump的命令,server就会源源不断的给client发送一个接一个的binlog event
2.3.1 Register
首先,需要伪造一个Slave,向matser注册,需要一个server_id来唯一的标识自己,并且向Master发送COM_REGISTER_SLAVE
命令,packet内还包括用户名、密码等信息
2.3.2 Binlog dump
这里不介绍GTID dump,通过指定binlog的文件名(filename)和位置(position)向Master发送COM_REGISTER_SLAVE
命令,在发送dump命令的时候还可以指定flag为BINLOG_DUMP_NON_BLOCK
在没有event之后会返回一个EOF
,也可以让Slave一直链接,持续收到新产生的Event
对于任意一个binlog文件,开头有4个字节的magic numberfe 62 69 6e
,通过这几个字节的内容确定文件的类型为binlog,因此position的值大于等于4
3. Binlog Event解析
3.1 整体结构
对于一个event来说,都有两个部分组成,分别是header头部和data数据两部分组成,在data内部又分为了固定的部分和可变空间
Binlog event 有很多版本,本文只讲解version4
3.1.1 Header
Header的固定长度为19字节,其中4个字节标识时间戳;type_code大小为1字节,用于标识event的类型;event_length是整个event的长度,包括header部分;next_position则是标识了下一个event所在的位置
+=====================================+
| event | timestamp 0 : 4 |
| header +----------------------------+
| | type_code 4 : 1 |
| +----------------------------+
| | server_id 5 : 4 |
| +----------------------------+
| | event_length 9 : 4 |
| +----------------------------+
| | next_position 13 : 4 |
| +----------------------------+
| | flags 17 : 2 |
+=====================================+
3.1.2 Data
针对不同的event类型,Data部分的数据都不相同,但是总体分为了fixed-part和variable-part两部分。而部分event的variable-part为空
3.2 Event解析
3.2.1 FORMAT_DESCRIPTION_EVENT
这部分主要描述了binlog和server的版本信息等,通常只需要关注post-header字段的,是一个byte类型的数组,保存每一类event中post-header的长度
+=====================================+
| 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 |
+=====================================+
解析代码
pos := 0
e.Version = binary.LittleEndian.Uint16(data[pos:])
pos