前言
redo log 和 bin log 这两个日志系统,都是用来存储更新操作的,不过他们存储的方式不同;
redo log 主要存储做了哪些修改,比如把name="javalover"改成 name="admin";
而bin log 不仅存储做了哪些修改,还存储修改的原始逻辑,比如update t set name=admin where id=1
,会同时存储这条语句和name="admin"最新值。
下面我们分别介绍下两者的工作流程和区别
目录
- redo log
- bin log
- change buffer
- 日志的执行流程
- 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的起点,如下所示:
当记录了1条数据后,write_point就会往前移动1次,而check_point不动:
当记录写满后,无法继续写入,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操作;
其次说下不同的地方:
- 更新操作:更新操作会先把更新记录写到change_buffer,然后再同步到redo log;
- 读取操作:如果在change buffer中读到了数据,那么就需要先将changge buffer中的脏页刷到磁盘中再读取;如果在change buffer中没有读到对应的数据,那么就会继续去redo log中查找;
- 磁盘IO:change buffer侧重于减少磁盘随机读的次数,而redo log侧重于减少磁盘随机写的次数;因为如果没有change buffer,那么每次的更新操作都会去读取磁盘而且是随机读,结果就是效率很低;
其实总结下来就是,不管读还是写,都是先去change buffer中操作,然后根据情况再看要不要去redo log中操作;
4. 日志的执行流程
这里我们以下面的语句为例子进行分析:这里假设系统用到了两个日志redo log和bin log
update t set age=10 where id=1;
- 执行器先去存储引擎中取出id=1的这行数据:如果这行数据所在的数据页在内存中,就直接返回;如果不在内存中,则需要先从磁盘读取对应的数据页,然后返回;
- 执行器拿到引擎返回的数据后,将对应的age设为10,并更新到内存中的数据页中,同时把操作记录保存到redo log中,此时redo log处于prepare状态;
- 接下来将操作记录存储到bin log中;
- 最后执行器提交事务,此时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找
评论区