听我讲完redo log、binlog原理,面试官老脸一红_redolog(1)

本文介绍了一位技术专家分享的关于Golang的学习资料,涵盖从入门到进阶,以及MySQL中重要日志如redolog和binlog的工作原理。作者强调了系统化学习的重要性,以及加入技术交流社区的价值。
摘要由CSDN通过智能技术生成

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

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

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

如果你需要这些资料,可以添加V获取:vip1024b (备注go)
img

正文

熊猫(老脸一红):emmm…精通就是,比面试官知道的多一点呗。。

在这里插入图片描述

面试官:(嗯。。。。是个老实人,我喜欢!)

面试官:那你先给我讲讲MySQL里有哪些比较重要的日志吧?

熊猫:(我只看了redo log、binlog面试题,咋整,多说会不会给自己挖坑?记得鲁迅大爷说过:别啥JB都说,最后坑自己)
在这里插入图片描述
熊猫:嗯。。其实MySQL中的日志有很多,但日常接触最多的是重做日志(redo log)、归档日志(binlog)这两种,当然还有回滚日志(undo log)等等,我接触的少一些。

MySQL日志主要包括六种:

  1. 重做日志(redo log)
  2. 回滚日志(undo log)
  3. 归档日志(binlog)
  4. 错误日志(errorlog)
  5. 慢查询日志(slow query log)
  6. 一般查询日志(general log)
  7. 中继日志(relay log)

面试官:好,那你先说一下你对 redo log 日志的理解吧。

熊猫:记得小时候看《武林外传》,吕秀才柜台下面有一个小黑板,当时不知道是干啥的,后来发现是专门用来记录客人的赊账记录。如果赊账的人不多,那么他可以把顾客名和账目写在板上。但如果赊账的人多了,小黑板没地儿了,这个时秀才一定还有一个专门记录赊账的账本。如果有人要赊账或者还账的话,秀才一般有两种做法:

  • 一种做法是直接把账本翻出来,把这次赊的账加上去或者扣除掉;
  • 另一种做法是先在小黑板上记下这次的账,等打烊以后再把账本翻出来核算。

在生意火爆时,秀才肯定会选择后者,因为直接记账本太麻烦了。得先翻出赊账人“老钱”那条记录,账本密密麻麻几十页,找到后再拿出算盘计算,最后更新到账本上。想想都麻烦。相比之下,还是先在小黑板上记一下方便。你想想,如果秀才没有小黑板的帮助,每次记账都得翻账本,效率是不是低得让人难以忍受?还有时间泡小郭?想无双?

在这里插入图片描述

同样,在 MySQL 里也有这个问题,如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程 IO 成本、查找成本都很高。为了解决这个问题,MySQL 的设计者就用了类似秀才记小黑板的思路来提升更新效率。

而小黑板和账本配合的过程,其实就是 MySQL 里经常说到的 WAL 技术

面试官:小伙子你这思路很奇特呀!那你再详细跟我说一下,啥是WAL技术?

熊猫:(小马哥对我有意思啊!)

WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写小黑板,等不忙的时候再写账本。

具体来说,当有一条update语句要执行的时候,InnoDB 引擎就会先把记录写到 redo log(小黑板)里面,并更新内存,这个时候更新就算完成了。

同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后秀才做的事。如果今天赊账的不多,掌柜可以等打烊后再整理。但如果某天赊账的特别多,小黑板写满了咋办?这个时候秀才只好叫无双帮忙干自己的活儿,抓紧把小黑板中的一部分赊账记录更新到账本中,然后把这些记录从小黑板上擦掉,为记新账腾出空间。

与此类似,InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 100MB,那么这块“小黑板”总共就可以记录 400MB 的操作记录。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。
在这里插入图片描述

  • write position 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。
  • checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

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

如果 write pos 追上 checkpoint,表示“小黑板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe

crash-safe:
  可以对照前面赊账记录的例子。只要赊账记录记在了小黑板上或写在了账本上,即使秀才突然被老邢抓走几天,回来后依然可以通过账本和小黑板上的数据明确赊账账目。就是维护数据的持久性。
  本质上说,crash-safe 就是落盘处理,将数据存储到了磁盘上,断电重启也不会丢失。

面试官:不错,你这理解虽说听的我一愣一愣,但是话糙理不糙,确实说出了redo log的原理。那你再说说对binlog日志的理解吧。

熊猫: 嘿嘿,谢谢马经理夸奖。MySQL 其实是分为 server层 和 引擎层两部分。

  • Server 层:它主要做的是 MySQL 功能层面的事情;
  • 引擎层:负责存储相关的具体事宜。

上面我们聊到的“小黑板” redo log 是 InnoDB 引擎特有的日志,而 Server 层也有自己的日志,称为binlog(归档日志),其实就是用来恢复数据用的。

面试官:那MySQL为啥要有redo log 和 binlog两个日志呢?只留一个不香么?

熊猫:因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,而 binlog 日志只用于归档。

InnoDB 是另一个公司以插件形式引入 MySQL 的。我们知道,只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。

面试官:那这两个日志主要有哪些区别?

熊猫:emmm…主要有几下几种区别:

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

面试官:好,基于你上面说的,那比如下面这条SQL,你来描述一下在MySQL内部的执行流程吧

update T set money = money + 500 where username = ‘陈哈哈’;

熊猫

  1. (开始,原始数据接入)执行器先找引擎取 username = ‘陈哈哈’ 这一行。如果 username = ‘陈哈哈’ 这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
  2. (数据修改)执行器拿到引擎给的行数据,把 money 这字段的值加上 500,比如原来是 N,现在就是 N+500,得到新的一行数据,再调用引擎接口写入这行新数据。
  3. (数据提交)提交操作,由于存储引擎层与server层之间采用的是内部XA(保证两个事务的一致性,这里主要保证redo log和binlog的原子性),所以提交分为prepare阶段与commit阶段,也就是我们说的两阶段提交
  4. (写redo log)引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面(写到内存或直接落盘),到这里, redo log 处于 prepare 状态。
  5. (写binlog)然后告知执行器执行完成了,随时可以提交事务。执行器生成这个操作的 binlog,并把 binlog 同步到磁盘。
  6. (数据更新到磁盘或内存,结束)执行器调用引擎的提交事务接口执行修改操作,需要将在二级索引上做的修改,写入到change buffer page,等到下次有其他sql需要读取该二级索引时,再去与二级索引做merge,引擎把刚刚写入的 redo log 标记上(commit)状态,实际上是加上了一个与binlog对应的XID,使两个日志逻辑保持一致,到此结束,更新流程闭环。

在这里插入图片描述


面试官:那为啥必须要分成prepare和commit两个阶段进行提交呢?一块儿提交他不爽么。

熊猫:我举个现实生活中的栗子吧,一个完整的交易过程我认为应该这样:

比如你来我的小超市里买一瓶可乐:

  1. 小马哥:老板给我来瓶可乐!透心凉心飞扬的那个。
  2. 我:??
  3. 机器扫一下可乐,告诉小马哥这瓶可乐2块5,不能白嫖,让他给钱(记录 redo log,事务处于prepare状态)
  4. 收钱放入钱箱(记录 binlog,事务实际是否完成的根本依据,处于待标记commit阶段)
  5. 然后让你把可乐拿走(redo log 状态标为 commit,表示该事务逻辑闭环)。到这里,代表一笔交易结束
  6. 并告诉小马哥,透心凉心飞扬那个是雪碧,你个憨X~
  7. 等算账前再把这一天卖东西的交易信息一起同步到数据库。

可见,如果收钱之前(prepare阶段,步骤3)交易被打断,回过头来处理此次交易,发现只有记了小黑板但没有收钱,则交易失败,删掉小黑板上的记录(回滚);

如果收了钱后(commit阶段 或 待commit阶段,步骤4 || 5)交易被打断,然后回过头发现系统上有记录(prepare)而且钱箱有本次收入(bin log),则说明本次交易有效,补充修改commit状态,更新到库存中。


以上是人话,咱们再来看看MySQL层面的专业解释:

这里我们用反证法来进行解释为何需要两阶段提交。由于 redo log 和 binlog 是两个独立的逻辑,如果不用两阶段提交,要么就是先写完 redo log 再写 binlog,或者采用反过来的顺序。我们看看这两种方式会有什么问题。

仍然用前面的 update 语句来做例子。假设当前 username = ‘陈哈哈’ 的行,账户余额字段 money 的值是 100,再假设执行 update 语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了 crash(异常宕机),会出现什么情况呢?

依旧以这条SQL为例:

update T set money = 0 + 500 where username = ‘陈哈哈’;

1、先写 redo log 后写 binlog。

假设在 redo log 写完,binlog 还没有写完的时候,MySQL 进程异常重启。由于我们前面说过的,redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 money 的值是 money + 500。
但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。
然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 money 的值就是 0,与原库的值不同。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-ldTmoKIX-1713474301630)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值