设为首页 加入收藏

TOP

MySQL复制(二) --- 二进制日志怎么干活的 (一)
2014-11-23 20:12:37 来源: 作者: 【 】 浏览:73
Tags:MySQL 复制 ---二进制日志 怎么 干活

之前的文章可以了解到,二进制日志在复制中起到举足轻重的作用,所以这一篇文章着重了解一下Mysql复制背后核心组件:二进制日志的庐山真面目。

二进制日志的结构

从概念上讲,二进制日志是一系列二进制日志事件。它包括一系列的binlog文件和一个binlog索引文件,当前服务器正在写入的binlog文件称之为active binlog。其文件名是通过配置文件中的log-bin和log-bin-index来定义的。

每个binlog文件是由若干binlog事件组成,以Format_description事件开始,以Rotate事件作为文件尾。

Format_description事件包含写binlog文件的服务器信息,以及关于文件状态的关键信息。如果服务器关闭或者重新启动,会创建一个新的binlog文件,同时写入新的Format_description事件,这个事件是必须的,因为服务器关闭和重启都会产生更新。服务器写完binlog文件后,在文件结尾添加一个Rotate事件,该事件包含下一个binlog文件的文件名及其开始读取的位置。除了Format_description和Rotate事件之外,binlog文件的其他事件都被分成 group进行管理。在事务存储引擎中,每个组大致对应一个事务,对于非事务存储引擎,每个语句本身就是一个组。通常情况下,每个组要么全部执行,要么去不执行。如果由于某种原因Slave在组执行的过程中停机,那么将从该组的起点而不是刚刚执行的语句开始复制。

binlog事件的结构

二进制日志版本4(binlog format 4)是在MySQL 5.0中引入,是专门为扩展而设计的。这里主要讨论二进制日志版本4。(MySQL 3.23 4.0 4.1版本都是使用二进制日志版本3)

每个binlog事件由三个部分组成:

  • 通用头(common header):大小固定。事件的基本信息,其中重要的字段是事件类型和事件大小。
  • 提交头(post header):大小固定。提交头与特定的事件类型相关
  • 事件体(Event body):大小可变。事件体存储事件的主要数据,因事件类型不同而异。

具体看一下Format_description事件:

  • binlog文件格式版本
  • 服务器版本字符串:一般包括三部分,即版本号、连字符和其他构建项。例如:5.1.42-debug-log
  • 通用头的长度:存储了通用头的长度。这里是指Format_description事件,所以不同binlog文件该字段的值不同。除了Format_description和Rotate事件外,其他事件的通用头长度都是可变的。Format_description事件的通用头长度是不变的,是因为任何版本的服务器都需要读取这个事件。Rotate事件的通用头长度也是不变的,是因为Slave连接Master时首先要用到该事件。
  • 提交头的长度:binlog文件中所有事件的提交头长度是不变的,该字段存储了各个事件的提交头长度构成的数组。由于不同服务器间的事件数目不同,所以这个字段前面还存储了服务器的事件数目。

通过事件来记录数据库变更

首先,由于二进制日志是公共资源,所有线程都向它写入语句,为了避免两个线程同时更新二进制日志,在写之前需要获得一个互斥锁Lock_log,写完之后再释放。

所有涉及到数据库更新的语句都会以Query事件的形式写入二进制日志中,除了实际执行的语句外,Query事件还包含执行语句必需的上下文附加信息。下面给出了如何记录这些上下文信息

  • 当前数据库:在Query事件添加一个特殊字段记录当前数据库。
  • 用户自定义变量的值:User_var事件记录单个用户自定义的变量的变量名及其值。
  • RAND函数的种子:Rand事件记录Rand函数所用的随机数种子。
  • 当前时间:NOW,CURDATE,CURTIME,UNIX_TIMESTAMP和SYSDATE这五个函数会用到当前时间,针对这个事件会存储一个时间戳,表示事件何时开始执行。
  • AUTO_INCREMENT字段的插入值:Intvar事件记录在语句开始前,表内部的自动增量计数器的值。
  • 调用LAST_INSERTED_ID的返回值:Intvar事件记录这个函数在语句的返回值。
  • 线程ID:主要是涉及到临时表的处理。线程ID也是作为一个独立的字段存储在Query事件中。

* 对于SYSDATE函数,它返回的是函数执行时的时间,这一点不同于NOW函数,NOW返回的是语句执行的时间。所以SYSDATE对于复制来说是不安全的,尽量少用。

LOAD DATA INFILE语句

LOAD DATA INFILE比较特殊,它的上下文是文件系统的文件。要正确地传递和执行LOAD DATA INFILE语句,需要引入新的事件类型:

  • Begin_load_query:这个事件开始传输文件中的数据
  • Append_block:如果这个文件超过了连接的数据包大小所允许的最大值,那么跟随在Begin_load_query事件后面的一个或多个Append_block事件的系列包含着这个文件的剩余部分
  • Execute_load_query:Query事件的特殊变种,它包含了在Master上执行的LOAD DATA INFILE语句

对Master上执行的每个LOAD DATA INFILE语句而言,被读取的文件被映射到一个支持内部文件的缓冲区,并在接下来的处理流程中使用。此外,一个唯一的文件ID被分配给该执行语句,并用于指向该语句读取的文件。

当语句在执行的时,该文件的内容被写入二进制日志,作为以Begin_load_query事件开头的事件序列,Begin_load_query事件表示新文件的开始,且这个事件序列后面紧跟着零个或多个Append_block事件。每个写入二进制的事件都不会超过包大小所允许的最大值,这个最大值由max-allowed_packet选项指定。

当整个文件读取到表中后,通过写Execute_load_query事件到二进制日志来终止语句的执行。这个事件包含了执行语句和分配给该执行语句的文件ID。请注意,这并非是用户写的原始语句,而是重新创建的。

* Mysql 5.0.3之前的版本使用的事件名有点不一样,依次为Load_log_event,Execute_log_event,Create_file_log_event

二进制日志过滤器

my.cnf中有两个选项可用于过滤日志:binlog-do-db和binlog-ignore-db。这两个选项可以使用多次。

MySQL过滤事件的方式对于不熟悉的人来说可能有点奇怪。Mysql过滤是在语句级完成的,binlog-*-db使用当前数据库来决定是否应该过滤该语句,而不是由语句所影响的表所在的数据库决定的。对于下面的例子,使用binlog-ignore-db=bad筛选bad数据库,下例中一个都不会写入日志。

	USE bad; INSERT INTO t1 VALUES (1),(2);
USE bad; INSERT INTO good.t2 VALUES (1),(2);
USE bad; UPDATE good.t1, ugly.t2 SET a = b;

至于为什么不是以语句所影响的表所在的数据库来决

首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇使用一条INSERT语句完成多表插入 下一篇EBS:Inventory模块的两个package:..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: