1. 前言
日志是MySQL的重要组成部分,其中对于开发而言不得不关注三种重要的日志,分别是二进制日志(bin log)、事务日志(redo log、undo log)。接下来详细介绍这三种日志。
2.MySQL三种重要日志
2.1 bin log
binlog叫做二进制日志,主要是用于记录MySQL表的逻辑变化过程。在实际应用过程中,通常被用于主从复制和数据恢复。
bin log的写入
事务执行过程中,会先把日志写到binlog cache,事务提交的时候,再把binlog cache写到binlog文件中。
事务提交后的写入只是写入到文件系统的page cache,并没有把数据持久化到磁盘。持久化磁盘由操作系统决定调用fsync。
MySQL提供了配置决定fsync的时机,当sync_binlog=0的时候,每次提交事务只写入page cache,不执行fsync。当sync_binlog=1的时候,表示每次提交事务都会执行fsync。当sync_binlog = N的时候,每次提交事务都写入page cache,累计多个事务才进行fsync。
显然,当sync_binlog = 1的时候,binlog日志不会丢失。当sync_binlog = N的时候,如果发生异常重启,会丢失N个事务的binlog日志。
bin log日志格式
STATEMENT
记录数据操作的原始SQL,可能引发主库备库因索引选择不一致,导致数据执行结果不一致。
ROW
ROW基于行复制,只记录哪条数据被修改.缺点:占空间。比如DELETE 语句,对于STATEMENT只占用1条SQL。而ROW格式则需要把所有记录的数据记录下来。
MIXED
对于可能引发主备不一致的命令使用ROW格式,否则使用STATEMTNT
2.2. redo log
对于每一次更新操作,MySQL都需要写入磁盘,然后需要找到对应那条记录并更新。IO成本较高和查找成本都很高。为了提高性能,MySQL会将更新操作写入redo log,并更新内存。INNODB引擎会在适当的时候将操作记录更新到磁盘。
写入过程
[图片上传失败...(image-c6a1f2-1627716309698)]
- write pos是当前记录的位置,一边写一边后移
- checkpoint是当前要写入磁盘的数据
- redo log的大小是固定的,从头开始写,写完末尾又重新回到开头循环写
2.3 undo log
undo log主要是记录了数据的逻辑变化,比如对应一条insear语句,undo log会记录一条delete语方便回退到更新前的值。
3. 数据更新过程
- MySQL 执行器调用存储引擎查找ID=2的数据。数据页在内存则直接返回,否则从磁盘读入再返回
- 执行器拿到行数据,将数据+1,再调用存储引擎接口写入这行数据
- 存储引擎将数据更新至内存,并将更新记录写入redo log。此时redo log出于prepare状态。然后存储引擎直接返回给执行器写入成功,可以提交事务了。
- 执行器生成binlog写入磁盘
- 执行器调用存储引擎提交事务。存储引擎将redo log改成提交状态,更新完成。
4. 崩溃恢复
- 恢复过程中如果redolog出于prepare状态。需要判断binlog是否存在并且完整
- a) 存在但不完整,回滚数据
- b) 存在且完整,提交事务
时刻A发生故障的话,由于binlog未写入,redo log回滚数据,两个日志数据是一致的。
时刻B发生故障,则需要判断binlog是否完整来决定如何恢复。
5. 思考
redo log和bin log的区别?
- redo log是InnoDB特有的;binlog是MySQL server层实现的
- redo log是物理日志,记录某个数据页上做了什么修改;bin log是逻辑日志记录语句的原始逻辑
- redo log是循环写入,空间固定会用完;binlog可以追加写入。
为什么redo log crash-safe,而bin log不可以?
- bin log仅仅是记录了数据的逻辑变化,并无法表示哪些数据已经刷入磁盘哪些数据还没有;
- redo log循环写,只会记录未刷盘的日志,已经刷盘的数据都会从redo log中删除。