MySQL是如何恢复到某一天的某一秒的状态?,34岁Java开发大叔感慨

说到存储引擎,MySQl 支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。也就是说,你执行 create table 建表的时候,如果不指定引擎类型,默认使用的就是 InnoDB。不过,你也可以通过指定存储引擎的类型来选择别的引擎,比如在 create table 语句中使用 engine=memory, 来指定使用内存引擎创建表。不同存储引擎的表数据存取方式不同,支持的功能也不同。

接下来,看一下写操作的执行过程,redo log 和 binlog 又起到了什么作用?

写操作

首先,可以确定的说,查询语句的那一套流程,更新语句也是同样会走一遍。

与查询流程不一样的是,更新流程还涉及两个重要的日志模块,它们正是redo log(重做日志)和 binlog(归档日志)。如果接触 MySQL,那这两个词肯定是绕不过的,redo log 和 binlog 在设计上有很多有意思的地方,这些设计思路也可以用到你自己的程序里。

以更新操作为例,假如 SQL 语句为:

update table_a set count = count + 1 where id = 2

复制代码

  1. 执行器先找引擎取 id=2 这一行。id 是主键,引擎直接用树搜索找到这一行。如果 id=2 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。

  2. 执行器拿到引擎给的行数据,把这个值加上 1,比如原来是 N,现在就是 N+1,得到新的一行数据,再调用引擎接口写入这行新数据。

  3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。

  4. 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。

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

这里得说明一下,redo log 和 binlog 都是日志文件,为了防止异常重启、掉电、恢复数据等场景,这些日志文件都会持久化到磁盘上。为了防止频繁的访问磁盘,写 redo log 前会先写到内存中的 redo log buffer,会定期一起写到磁盘。

但是这两个 log 文件又有所区别:

  1. redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 层实现的,所有引擎都可以使用。

  2. redo log 是物理日志,记录的是“在某个数据页上做了什么修改”;binlog 是逻辑日志,记录的是这个语句的原始逻辑,比如“给 id=2 这一行的 c 字段加 1 ”。

  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

  4. redo log 用于回滚,binlog 用于恢复。

如果将 MySQL 恢复到某一天的某一秒

要做到这一点有个前提,就是要对 MySQL 数据库定期做整库备份。这里的定期取决于系统的重要性,可以是一天一备,也可以是一周一备。

当需要恢复到指定的某一秒时,比如某天下午两点发现中午十二点有一次误删表,需要找回数据,那你可以这么做:

  1. 首先,找到最近的一次全量备份,如果你运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时库;

  2. 然后,从备份的时间点开始,将备份的 binlog 依次取出来,重放到中午误删表之前的那个时刻。这样你的临时库就跟误删之前的线上库一样了。

  3. 最后,你可以把表数据从临时库取出来,按需要恢复到线上库去。

为什么要两阶段提交

前面写操作中的提到,写磁盘前先写 redo log,此时 redo log 状态为 prepare,然后再写 binlog,写完 binlog 后,再提交,redo log 才处于 commit 状态。

为什么要等 binlog 写完才能提交呢? 这是因为假如 binlog 没写完就提交,此时如果异常重启,那么 binlog 就没有这条记录,在后续的主从复制时,将该 binlog 重放之后,从库的数据与主库的数据就产生了不一致。

如果先写 binlog,再写 redo log,假如写完 binlog 系统异常重启,那么重启恢复后由于 redo log 还没有写,因此事务回滚,但是由于 binlog 已经成功写入,在后续的主从复制后仍然导致主从不一致。

MySQL 如何回滚与恢复数据的?

前面提到 InnoDB 有个日志文件叫 redo log,就可以持久化存在磁盘上的,但是在内存中也有一份对应的缓冲区,叫 redo log buffer,为了应对异常重启,InnoDB 有一个后台线程,每隔 1 秒,就会把 redo log buffer 中的日志,调用 write 写到文件系统的 page cache,然后调用 fsync 持久化到磁盘。

也就是 redo log buffer -> page cache -> 磁盘 这一过程,每秒都在进行,一旦发生异常重启,从 redo log 中恢复就可以了。那具体是怎么恢复的呢?

事务提交之前,先写入 redo log,状态是 prepare,表示已经准备好了,随时可以提交。

事务提交之后,redo log 对应的状态是 commit,表示已经提交。

如果是 prepare 时发生异常重启,mysql 在恢复后对状态为 prepare 状态的事务进行回滚。

如果是 commit 状态,表示本来已经写完了,重启也没关系。

如果是 prepare 之前崩溃了,也无所谓,本来就没有开始写数据,重启也没有任何损失。

现在有了 redo log,只能保证数据不丢,但还无法保证数据可以恢复到之前的某一时刻的状态。

这就需要 binlog,binlog 是 mysql 自带的归档日志。

假如在写 binlog 前异常重启,mysql 在恢复后对状态为 prepare 状态的事务进行回滚。

假如在写 binlog 后异常重启,则判断对应的事务 binlog 是否存在并完整:

a. 如果是,则提交事务; b. 否则,回滚事务。

你可能会问,处于 prepare 阶段的 redo log 加上完整 binlog,重启就能恢复,MySQL 为什么要这么设计?

回答: binlog 写完以后 MySQL 发生崩溃,这时候 binlog 已经写入了,之后就会被从库(或者用这个 binlog 恢复出来的库)使用。所以,在主库上也要提交这个事务。采用这个策略,主库和备库的数据就保证了一致性。

还有一个问题,就是为什么不让 redo log 也承担 binlog 的功能?

这是因为,redo log 是循环写的,写完后会从开头继续写,这样 redo log 就无法记录一段时间内的完整操作,这样历史日志没法保留,redo log 也就起不到归档的作用。

另一个原因就是就是 MySQL 系统依赖于 binlog。binlog 作为 MySQL 一开始就有的功能,被用在了很多地方。其中,MySQL 系统高可用的基础,就是 binlog 复制。还有很多公司有异构系统(比如一些数据分析系统),这些系统就靠消费 MySQL 的 binlog 来更新自己的数据。关掉 binlog 的话,这些下游系统就没法输入了。

最后的话

MySQL 的奥妙就在于 redo log 和 binlog 的完美配合,这样的模式保证了系统可以应对异常重启,也保证了数据可以恢复到某一天的任意一秒的状态,当然这是在有完整备份的前提下,其实这样的设计可以迁移到平时软件设计上,比如说涉及用户输入的系统,在发生异常重启、掉电的情况下,如何让用户的输入不丢失,系统的配置文件比较复杂被改乱了,如何快速恢复到某一天之前的配置状态等。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

总结

面试难免让人焦虑不安。经历过的人都懂的。但是如果你提前预测面试官要问你的问题并想出得体的回答方式,就会容易很多。

此外,都说“面试造火箭,工作拧螺丝”,那对于准备面试的朋友,你只需懂一个字:刷!

给我刷刷刷刷,使劲儿刷刷刷刷刷!今天既是来谈面试的,那就必须得来整点面试真题,这不花了我整28天,做了份“Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法等”

image

且除了单纯的刷题,也得需准备一本【JAVA进阶核心知识手册】:JVM、JAVA集合、JAVA多线程并发、JAVA基础、Spring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

image

ring 原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB、Cassandra、设计模式、负载均衡、数据库、一致性算法、JAVA算法、数据结构、加密算法、分布式缓存、Hadoop、Spark、Storm、YARN、机器学习、云计算,用来查漏补缺最好不过。

[外链图片转存中…(img-Y40v2gpi-1712098999731)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值