今天我们就来深挖一下MySQL的复制机制以及binlog和relay-log的结构是什么样的。binlog的作用binlog的主要作用是记录数据库中表的变化。它只记录改变数据的sql,不改变数据的sql不会被写入。例如,select语句一般不会被记录,因为它们不会对数据做任何改变。.用一个实际场景来看binlog生成的过程,准备sql:createtabletest(textvarchar(20));insertintotestvalues('test_text');select*fromtest;flushlogs;查看binlogshowbinlogeventsin'binlog.000029';显示结果如下:binlog另外,还可以使用mysqlbinlog工具查看binlog的内容:showvariableslike'log_%';#查看日志目录mysqlbinlog--short-form--force-if-open--base64-output=never/usr/local/var/mysql/binlog.000029从日志中我们可以看到创建语句表和Format_desc标题和Ratate旋转事件被执行。这个以后再说,我们先看看几个字段代表的含义。Log_name表示日志文件的名称。比如我这里的查询是直接查询binlog.000029。默认的写法是showbinlogevents,但是这样只会查询第一个binlog,不会查询当前激活的binlog。如果不知道什么是binlog,可以使用命令:showbinarylogs;#查看binlog列表showmasterstatus;#查看最新的binlogPos表示文件的起始位置。Event_type表示事件的类型。Server_id是创建事件的服务器ID。End_log_pos表示事件在文件中的结束位置。以上面为例,第一次查询的结束位置是723,第二次插入后文件的起始位置是723。Info代表事件信息,是可读的文本内容。Binlog日志结构binlog日志的结构大致是这样的。它由一个索引文件和一个二进制日志文件组成。binlog事件由三部分组成:通用头、提交头、事件体。首先,让我们谈谈索引文件。索引文件的每一行包含一个binlog文件的完整文件名(类似于host-bin.001)。一些命令如flushlogs将所有日志写入磁盘,会影响索引文件。每个binlog文件由若干个binlog事件组成,以格式描述事件(Format_description)作为文件头(上面的binlog图像Format_desc事件),以日志轮转事件(rotate)作为文件尾。format_description包含了binlog文件的服务器信息,文件状态的关键信息等,如果服务器关闭或者重启,会创建一个新的binlog文件,写入新的format_description。他的格式大致如下。2binlog-versionstring[50]mysql-serverversion4createtimestamp1eventheaderlengthstring[p]eventtypeheaderlengthslogrotationevent包含下一个binlog的文件名和开始读取的位置,在server写入binlog后添加到文件末尾,以及旋转事件不是每次都存在,格式如下。ifbinlog-version>1{8position}string[p]nameofthenextbinlogbinlog事件包含若干个事务组(group),每个组对应一个事务,如果createalter语句不属于该事务语句,那么它们本身就是一个组,每个组要??么全部执行,要么不执行。Binlog事件结构每个binlog事件由3部分组成:Generalheader,包含了binlog中所有事件的基本信息。提交头,对于不同类型的事件,提交头的内容也不同。事件主体,存放的是事件的主要数据,不同类型的事件也不同。Binlog轮转和清理从上面的例子我们也可以看出,binlog并不是只有一个,根据实际场景,总写一个binlog文件是肯定不可取的,而binlog轮转主要有以下三种场景:服务器startup,服务器每次启动都会生成一个新的binlog文件。当达到最大尺寸时,大小可以通过binlog-cache-size来控制,达到最大尺寸后会被替换掉。显示刷新,刷新日志会将所有日志写入磁盘。这时候会新建一个文件并写入。从第一个例子可以看出,执行后会生成一个新的日志binlog.000030文件,起始位置为4。随着时间的推移,我们的binlog文件会越来越多。这时候清除binlog有两种方法:通过设置expire-logs-days来控制你想保留binlog日志文件的天数,系统会自动清理它们。通过PURGEBINARYLOGS手动清除relay-log结构relay-log中继日志是连接master和slave的核心。让我们深入了解一下它的结构和使用。image-20200909161115718relay-log的结构和binlog非常相似,只是多了一个master.info和relay-log.info文件。master.info记录了上次从master读取并同步的binlog的位置,以及连接到master和开始复制所需的所有信息。relay-log.info记录了文件复制的进度,下一个事件从哪里开始,sql线程负责更新。在上一篇文章中,我们提到整个复制过程是这样的:在知道了binlog和relay-log的结构后,我们重新梳理了整个链接过程。这里我们假设master.info和relay-log.info都是有一种情况:Master收到一条客户端请求语句,在语句结束前向二进制日志写入一条记录,其中可能包含多个事件。此时有一个Slave连接到Master上,Master的dump线程从binlog中读取日志发送给Slave的IO线程。IO线程从master.info读取到上次写入的最后一个位置。IO线程将日志写入relay-log中继日志。如果超过指定的中继日志大小,则写入轮换事件并创建新的中继日志。更新master.info的最后位置SQL线程从relay-log.info读取到最后读取的位置SQL线程读取日志事件在数据库中执行SQL更新relay-log.info的最后位置Slave记录自己的binlog日志但是这里IO和SQL线程存在事件重复的问题。这里有一个场景:先记录relaylog,然后更新master.info的位置。此时服务器崩溃,写入master.info失败。服务器恢复并再次从主服务器同步。info获取的信息是最后一个位置,会导致事件重复执行。既然有这样的问题,我们为什么要这样做呢?假设反过来,先更新master.info,再记录relaylog,这样造成的问题就是数据丢失。而mysql认为丢失比重复更严重,所以应该先刷新日志,mysql会帮你决定是留大还是留小。
