【读书笔记】MySQL实战45讲——日志系统

课程来自极客时间《MySQL实战45讲》


在这里插入图片描述

一、redo log:InnoDB引擎特有

redo log不是记录数据页“更新之后的状态”,而是记录这个页 “做了什么改动”。

MySQL里有这个问题,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程IO成本、查找成本都很高。

为了解决这个问题,MySQL提出了WAL(Write-Ahead Logging)技术:先写日志,再写磁盘

具体来说,当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log里面,并更新内存,这个时候更新就算完成了。

同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做。

redo log大小固定,比如可以配置为一组4个文件,每个文件的大小是1GB,那么这块“粉板”总共就可以记录4GB的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。
在这里插入图片描述
write pos是当前记录的位置,一边写一边后移。

checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

write pos和checkpoint之间的是“粉板”上还空着的部分,可以用来记录新的操作。

1、crash-safe

有了redo log,IInnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失

1.1、如何保证提交记录不丢失?

redo log是物理日志,记录的是“在某个数据页上做了什么修改”,发生异常重启时,只需要按照redo log就可以恢复之前提交的数据记录,这也就是crash-safe

二、binlog:Server层特有

binlog日志只能用于归档

binlog有两种模式,statement 格式的话是记sql语句, row格式会记录行的内容,记两条,更新前和更新后都有。

1、如何让数据库恢复到半个月内任意一秒的状态?

binlog记录所有的逻辑操作,并且是采用“追加写”的形式,系统如果定期备份和备份binlog,那么当需要恢复当指定的某一秒时,拿出离这一秒最近的一次全量备份,然后从这个时间点开始,将备份的binlog依次取出来,重放到误删你需要的那个时刻。

2、为什么binlog没有crash-safe的功能?

如果只用binlog来实现崩溃恢复的流程
在这里插入图片描述
binlog没有能力恢复“数据页”

如果在图中标的位置,也就是binlog2写完了,但是整个事务还没有commit的时候,MySQL发生了crash。

重启后,引擎内部事务2会回滚,然后应用binlog2可以补回来;但是对于事务1来说,系统已经认为提交完成了,不会再应用一次binlog1。

但是,InnoDB引擎使用的是WAL技术,执行事务的时候,写完内存和日志,事务就算完成了。如果之后崩溃,要依赖于日志来恢复数据页。

也就是说在图中这个位置发生崩溃的话,事务1也是可能丢失了的,而且是数据页级的丢失。此时,binlog里面并没有记录数据页的更新细节,是补不回来的。

如果要说,那我优化一下binlog的内容,让它来记录数据页的更改可以吗?但,这其实就是又做了一个redo log出来。

3、redolog与binlog的不同

  1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
  2. redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。
  3. redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

三、两阶段提交

在这里插入图片描述
通过上图可知

引擎更新新数据到内存的同时把更新操作记录到redo log,此时的redo log处于prepare状态

接着执行器生成此操作的binlog,并且把binlog写入磁盘

执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交(commit)状态,更新完成

1、两阶段提交的重要性

反证法证明

  1. 先写redo log后写binlog如果redo写完,binlog还没写完,MySQL进程异常重启,那么此时的redo log完整,可以进行crash-safe恢复数据。但是binlog还未写完,所以之后如果需要用这个binlog来恢复临时库的话,由于此binlog未写完导致丢失,库里就不会记录这次的更新,恢复出来的数据就跟原来的不同
  2. 先写binlog后写redo log如果在binlog写完之后crash,由于redo log还没写,崩溃恢复以后这个事务无效,无法恢复数据。但是binlog里面已经记录了数据改动的日志。所以,在之后用binlog来恢复的时候就多了一个事务出来,恢复出来的数据将与原库的值不同。

2、在两阶段提交的不同时刻,MySQL异常重启会出现什么现象

  1. redo处于prepare阶段之后、写binlog之前,发生了崩溃(crash),由于此时binlog还没写,redo log也还没提交,所以崩溃恢复的时候,这个事务会回滚。这时候,binlog还没写,所以也不会传到备库。
  2. binlog写完,redo log还没commit前发生crash,崩溃恢复过程中事务会被提交

2.1、崩溃恢复时的判断规则

  1. 如果redo log里面的事务是完整的,也就是已经有了commit标识,则直接提交;
  2. 如果redo log里面的事务只有完整的prepare,则判断对应的事务binlog是否存在并完整:
    a. 如果是,则提交事务;
    b. 否则,回滚事务。

2.2、MySQL怎么知道binlog是完整的?

一个事务的binlog是有完整格式的:

  • statement格式的binlog,最后会有COMMIT;
  • row格式的binlog,最后会有一个XID event。

另外,在MySQL 5.6.2版本以后,还引入了binlog-checksum参数,用来验证binlog内容的正确性。对于binlog日志由于磁盘原因,可能会在日志中间出错的情况,MySQL可以通过校验checksum的结果来发现。所以,MySQL还是有办法验证事务binlog的完整性的。

2.3、redo log 和 binlog是怎么关联起来的?

它们有一个共同的数据字段,叫XID。崩溃恢复的时候,会按顺序扫描redo log:

  • 如果碰到既有prepare、又有commit的redo log,就直接提交;
  • 如果碰到只有parepare、而没有commit的redo log,就拿着XID去binlog找对应的事务。

3、能不能只用redo log,不要binlog?

只从崩溃恢复的角度上讲可以,只靠redo log就可以crash-safe

  1. 归档问题。redo log循环写,历史日志无法保留,redo log起不到归档作用
  2. MySQL系统高可用的基础就是binlog复制,MySQL系统依赖于binlog,而redo log只在InnoDB中存在

四、问题

“取决于系统重要性,有的是一天一备,有的是一周一备”。那么在什么场景下,一天一备会比一周一备更有优势呢?或者说,它影响了这个数据库系统的哪个指标?

答案:好处是“最长恢复时间”更短。

在一天一备的模式里,最坏情况下需要应用一天的binlog。比如,你每天0点做一次全量备份,而要恢复出一个到昨天晚上23点的备份。

一周一备最坏情况就要应用一周的binlog了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值