MySQL学习-日志系统 redo log 和 bin log

「这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

作者:汤圆

个人博客:javalover.cc

前言

redo log 和 bin log 这两个日志系统,都是用来存储更新操作的,不过他们存储的方式不同;

redo log 主要存储做了哪些修改,比如把name="javalover"改成 name="admin";

而bin log 不仅存储做了哪些修改,还存储修改的原始逻辑,比如update t set name=admin where id=1,会同时存储这条语句和name="admin"最新值。

下面我们分别介绍下两者的工作流程和区别

目录

  1. redo log
  2. bin log
  3. change buffer
  4. 日志的执行流程
  5. redo log 和 bin log 的区别

正文

1. redo log

redo log 重做日志,它属于存储引擎层,是InnoDB特有的的,MyISAM引擎不支持;

空间大小:

redo log 占用的空间大小是固定的,比如我们给redo log分配了4个文件,每个文件占用1G,那么redo log的固定大小就是4G;

当redo log 写满时,会执行合并操作,就是将redo log中的记录合并到数据库磁盘中;

这里也顺带引出了一个WAL的概念;

WAL机制:

全称为 write ahead logging,大致意思就是先写日志,再写磁盘,目的就是提高性能;

因为如果每一次的更新操作都要写进磁盘,那么就需要先把数据页从磁盘中取出来,然后更新,最后写到磁盘中;

这样一来,磁盘的随机IO成本会很高;

所以通过WAL机制,先把更新操作记录到redo log中,然后在系统空闲时,再合并到磁盘中,此时的合并是顺序写入的,磁盘的IO成本很低;

write_point 和 check_point:

write_point 写入点 和 check_point 擦除点,可以理解为两个指针,write_point负责指向待写入记录的位置,而check_point负责指向待擦除的位置;

可以把这两个点想象成铅笔和橡皮擦;

刚开始的时候,这两个指针都指的是redo log的起点,如下所示:

image-20211123164303658

当记录了1条数据后,write_point就会往前移动1次,而check_point不动:

image-20211123164729273

当记录写满后,无法继续写入,check_point就会往前移动,把记录合并到数据库中,然后清除掉该部分记录;

crash-safe:

这个crash-safe,指的是当MySQL服务异常重启时,之前提交的记录也不会丢失;

这个crash-safe是基于redo log实现的,而redo log又是InnoDB引擎特有的,所以很多时候我们都推荐用InnoDB引擎,因为更加安全;

2. bin log

bin log 归档日志,属于Service层的东西,跟存储引擎无关;

也就是说:bin log不仅支持InnoDB引擎,还支持MyISAM引擎;

既然有了redo log为啥还要有bin log呢?

其实是先有的bin log,后有的redo log;

刚开始的时候,MySQL的存储引擎只有MyISAM引擎,而MyISAM引擎只支持bin log,也就是归档日志,它并不具备crash-safe的能力;

后来有了InnoDB引擎,它支持redo log 重做日志,相应的也就有了crash-safe能力;

看起来好像bin log没啥用了,那为啥MySQL不直接取消bin log呢?

因为有的MySQL还是用的MyISAM引擎,取消掉bin log的话,那他们连最基本的日志记录都没有了;

3. change buffer

上一篇我们有介绍change buffer,在更新操作时,会把更新记录存储到change buffer;

那change buffer和redo log有什么关系呢?

首先说下相同的地方:其实他俩的目的是一致的,都是为了减少磁盘的IO操作;

其次说下不同的地方:

  1. 更新操作:更新操作会先把更新记录写到change_buffer,然后再同步到redo log;
  2. 读取操作:如果在change buffer中读到了数据,那么就需要先将changge buffer中的脏页刷到磁盘中再读取;如果在change buffer中没有读到对应的数据,那么就会继续去redo log中查找;
  3. 磁盘IO:change buffer侧重于减少磁盘随机读的次数,而redo log侧重于减少磁盘随机写的次数;因为如果没有change buffer,那么每次的更新操作都会去读取磁盘而且是随机读,结果就是效率很低;

其实总结下来就是,不管读还是写,都是先去change buffer中操作,然后根据情况再看要不要去redo log中操作;

4. 日志的执行流程

这里我们以下面的语句为例子进行分析:这里假设系统用到了两个日志redo log和bin log

update t set age=10 where id=1;
复制代码
  1. 执行器先去存储引擎中取出id=1的这行数据:如果这行数据所在的数据页在内存中,就直接返回;如果不在内存中,则需要先从磁盘读取对应的数据页,然后返回;
  2. 执行器拿到引擎返回的数据后,将对应的age设为10,并更新到内存中的数据页中,同时把操作记录保存到redo log中,此时redo log处于prepare状态;
  3. 接下来将操作记录存储到bin log中;
  4. 最后执行器提交事务,此时redo log变为commit状态,到此更新就完成了;

这里面涉及到一个两阶段提交的概念;

两阶段提交

就是对于redo log来说,不是一次就写入完成的,而是分两次;

第一次写入记录时设置为prepare状态,然后等待着bin log日志的写入;

等到bin log写入成功后,事务才会提交,此时redo log被引擎设置为commit状态;

这样做的目的就是保证事务的一致性,即redo log和bin log都拥有一致的更新记录;

5. redo log 和 bin log的区别

上面基本都有涵盖到,这里用表格来说明一下,比较清晰:

redo log bin log
存储引擎 InnoDB InnoDB, MyISAM
MySQL架构层 存储引擎层 Service服务层
存储方式 物理日志,存储做了哪些修改 逻辑日志,存储修改的逻辑语句以及结果
空间占用 大小固定,写满后需清空部分记录 可追加写入

总结

redo log属于InnoDB引擎特有,支持crash-safe,也就是MySQL服务异常重启后,之前提交的数据记录还能找见;

bin log属于Service层,所有引擎都支持,大小不固定,可追加写入;

change buffer 和 redo log相辅相成:更新数据会先写入到change buffer,再写入redo log;查询数据先去change buffer找,找不到再去redo log找

猜你喜欢

转载自juejin.im/post/7034418770709839902