中执行的语句分开,保存在一个事务缓存中,在事务提交的时候缓存被清空,同时事务缓存的内容被复制到二进制日志中。
那如何记录非事务性的语句呢?有这么三条规则可以使用:
- 如果语句被标记成事务的,它将被写入事务缓存
- 如果语句没有被标记成事务性的,而且事务缓存中没有语句,该语句将被直接写入二进制日志
- 如果语句没有被标记成事务性的,但是事务缓存中已有语句,该语句被写入事务缓存
如果一个事务里面涉及到非事务性语句时候,确保影响非事务性表的语句在事务中首先被写入,此时根据规则2会直接写入二进制日志。如果在事务的后面语句中,需要从这些语句中取到任何值,可以分配他们到临时表或变量。
使用XA进行分布式事务处理
XA包含一个事务管理器,协调一系列的资源管理器,以便于它们将一个全局的事务当作一个原子单元进行提交。每个事务都被分配一个唯一的XID,这个XID被事务管理器和资源管理器使用。当在MySQL服务器内部使用时,事务管理器通常是二进制日志而资源管理器是存储引擎。
提交一个XA事务的过程:
- 第一阶段,每个存储引擎被要求为提交做准备。在准备时,存储引擎将它需要正确提交的一切信息写入到安全的存储器,然后返回一个OK消息。如果有一个存储引擎的回答是否定的,则意味着它不能提交这个事务,提交被终止,而且所有的引擎都被通知回滚事务。
- 在所有的存储引擎都返回OK的时候,在第二阶段开始之前,事务缓存被写入二进制日志。普通事务以带有COMMIT的普通查询事件结束,与此同时,XA事务则以一个包含XID的Xid事件结束。
在第二阶段,在第一阶段中准备好的所有存储引擎都被要求提交事务。当提交时,每个存储引擎都将报告它已经在持久存储器中提交了事务。理解提交不能失败是非常重要:一旦阶段一已经通过,存储引擎就要保证事务能被提交,从而不能在阶段2报告失败。即使硬件错误导致系统崩溃,但是由于存储引擎已经在持久存储引擎中存储了这些信息,在服务器重启后,它们将能够正确恢复。恢复流程大概是:启动时,服务器将打开最后一个二进制日志并检查Format description事件。如果binlog-in-use标志被设置,那么表示服务器已经崩溃而且需要执行XA恢复。服务器通过查看活动的二进制日志来读取Xid事件,并从二进制日志中查找所有事务的XID。每个存储引擎启动后马上被要求提交列表中的事务。对于列表中每个XID,存储引擎将确定哪个XID对应的事务是已经准备好但没有提交的,如果是就提交这个事务。如果存储引擎准备的事务XID不在此列表中,那么这个XID显然在服务器崩溃前没有被写入二进制日志,因此这个事务必须被回滚。
二进制日志管理
到目前为止,所提到的事件都是Master上的数据的改动。有一些事件虽然不是代表在Master上修改数据,但它们却会影响复制。比如在服务器停止的期间修改了数据文件之类,为了应对这些问题,也需要额外类型的事件。
二进制日志和系统崩溃安全
在数据库崩溃的时候,保持数据库和二进制日志相互一致性非常重要。换句话说,如果没有写入二进制日志,那么就应该没有更改被提交到存储引擎,反之亦然。
但对于非事务性引擎则有问题。例如,不可能保证二进制日志和MyISAM表之间的一致性,因为MyISAM是非事务性的,且MyISAM在试图记录语句之前就完成了修改。对于事务性存储引擎则不一样。正如前面所讲,事件被写入二进制日志是在释放所有表锁之前,所有改变传输到各个存储引擎之后的。如果在存储引擎释放锁之前系统宕机了,服务器在允许事务提交之前一定要确认写进二进制日志的改变已经写进实际表中,而这是需要和标准文件系统同步进行协调。
回忆一下XA,为了能安全应对宕机,当第一阶段完成的时候,所有的数据都应该已经写到了磁盘。这就意味着每次一个事务完成,系统页缓存(page cache)就必须写到磁盘,这种想法的代价很高,而且很多应用并不必须这样。可以通过sync-binlog选项来控制数据写磁盘的频率,默认为0,也就是不写磁盘的调度完全交给操作系统;设置n,表示每n次事务提交就写一次磁盘。
binlog文件轮换(binlog file rotate)
MySQL隔一段时间就会启用一个新文件来保存二进制日志事件。把文件切换称之为binlog file rotate。
主要有四种操作会导致文件轮换:
- 服务器停止:每次服务启动都会启用一个新的二进制日志文件。
- binlog文件大小达到最大值:这个值可以通过binlog-cache-size参数控制。
- 显式刷新:FLUSH LOGS
- 服务器发生事故:有些事故需要特殊的人工干预,这都会在复制流程上形成一个"缺口"
每个二进制日志都是以Format description事件开始的,该事件描述服务器的信息以及文件的状态和内容的信息。其中有几个需要关注:
- binlog-in-use标志位:服务器在写二进制日志时有可能发生宕机,因此需要知道一个文件是否被正确的关闭。而且,如果一个文件本身损坏了,用它进行恢复会产生更多的问题。binlog-in-use就是用于标识一个文件的完整性,它在文件创建的时候被设置,在Rotate事件被写入文件后被清除。
- 二进制日志文件格式版本号:
- 服务器版本:
为了使得即使是在宕机的情况下,也能安全的切换日志文件,服务器采用了预写策略,在一个临时文件里写明其意图,该临时文件被称为purge index file(之所以这么叫是因为在清除二进制日志时它也被使用了),文件名是基于二进制日志索引文件名。当创建了新的二进制日志文件,并更新了索引文件之后,服务器会删除该临时文件。
Incidents
所谓incident事件是指那些在服务器上没有产生数据改变但却必须要写进二进制日志的事件,因为它们有可能影响到复制。大多数这种事件并不需要DBA干预,比如数据库的重启等。
- stop:这是一种表示服务器正常关机的事件。如果服务器宕机,就不会有stop事件。这个事件会在旧的二进制日志文件里,因为重启会启用新文件。该事件仅仅包含一个通用头。当二进制日志在Slave上重放的时候,所有Stop事件都会被忽略。那这种事件有什么用呢,因为重启复制前可能手动恢复一个备份或者修改了文件,这时候DBA在重放该日志文件的时候,可以找到该事件从而知道在哪里开始或者停止重放。
- Incident:该事件类型是在MySQL 5.1版本引入的。和Stop事件相比,该事件包含一个标志符来指定发生了哪种类型事故。它一般用来表示服务器被强制执行某个不被记入二进制日志的变更。比如,数据库重新加载,某个非事务性事件太大而无法写入二进制日志。MySQL Cluster在其中一个节点重新加载数据库而因此不同步时也会产生该事件。当二进制日志在Slave上重放的时候,碰到Incident事件的时候将会停止复制。
删除二进制文件
有几种方式可以删除二进制文件:
1:设置my.cnf的expire-logs-days参数
2:PURGE BINARY LOGS BEFORE datetime;
3:PURGE BINARY LOGS TO 'filename';
删除二进制文件的机制:
开始删除文件之前,服务器会把要删除的