日志相关问题
binlog(归档日志)和redo log(重做日志)配合崩溃恢复的时候,用的是反证法,说明了如果没有两阶段提交,会导致MySQL出现主备数据不一致等问题。
在两阶段提交的不同瞬间,MySQL如果发生异常重启,是怎么保证数据完整性的?
我再放一次两阶段提交的图,方便你学习下面的内容。

接下来,我们就一起分析一下在两阶段提交的不同时刻,MySQL异常重启会出现什么现象。
1.如果在图中时刻A的地方,也就是写入redo log 处于prepare阶段之后、写binlog之前,发生了崩溃(crash),由于此时binlog还没写,redo log也还没提交,所以崩溃恢复的时候,这个事务会回滚。这时候,binlog还没写,所以也不会传到备库。到这里,大家都可以理解。
2.如果在图中时刻B的地方,也就是binlog写完,redo log还没commit前发生crash,那崩溃恢复的时候MySQL会怎么处理?
我们先来看一下崩溃恢复时的判断规则。
-
如果redo log里面的事务是完整的,也就是已经有了commit标识,则直接提交;
-
如果redo log里面的事务只有完整的prepare,则判断对应的事务binlog是否存在并完整: a. 如果是,则提交事务; b. 否则,回滚事务。
这里,时刻B发生crash对应的就是2(a)的情况,崩溃恢复过程中事务会被提交。
现在,我们继续延展一下这个问题。
追问1:MySQL怎么知道binlog是完整的?
回答:一个事务的binlog是有完整格式的:
-
statement格式的binlog,最后会有COMMIT;
-
row格式的binlog,最后会有一个XID event。
另外,在MySQL 5.6.2版本以后,还引入了binlog-checksum参数,用来验证binlog内容的正确性。对于binlog日志由于磁盘原因,可能会在日志中间出错的情况,MySQL可以通过校验checksum的结果来发现。所以,MySQL还是有办法验证事务binlog的完整性的。
追问2:redo log 和 binlog是怎么关联起来的?
回答:它们有一个共同的数据字段,叫XID。崩溃恢复的时候,会按顺序扫描redo log:
-
如果碰到既有prepare、又有commit的redo log,就直接提交;
-
如果碰到只有parepare、而没有commit的redo log,就拿着XID去binlog找对应的事务。

被折叠的 条评论
为什么被折叠?



