一、两个重要的日志模块
与查询流程不一样的是,更新流程还涉及两个重要的日志模块。
redo log(重做日志)
redo log 也是事务中持久性实现的原理,它是存储引擎层的。如果每一次的更新操作都需要写进磁盘,然后磁盘也要找到对应的那条记录,然后再更新,整个过程IO成本、查找成本都很高。
WAL技术:WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘。
write pos是当前记录的位置,checkpoint是当前要擦除的位置,图中checkpoint 和writepoint 之间是记录的日志,redo log是循环利用并且是固定大小的。比如可以配置4个文件,每个文件的大小是1G, 那么redo log 总共可以记录4G 的操作记录。
crash-safe:有了redo log ,InnoDB 可以保证异常启动后记录仍然不对丢失,这个能力即使crash-safe。
binlog(归档日志)
redo log是InnoDB引擎特有的日志,而Server层也有自己的日志,称为binlog(归档日志)。
MySQL里并没有InnoDB引擎之前,MySQL自带的引擎是MyISAM,但是MyISAM没有crash-safe的能力,binlog日志只能用于归档。而InnoDB是另一个公司以插件形式引入MySQL的,既然只依靠binlog是没有crash-safe能力的,所以InnoDB使用另外一套日志系统——也就是redo log来实现crash-safe能力。
两种日志的三点不同:
- redo log 是InnoDB 引起所特有的;binlog 是MySQL 的service 层实现的,所有引擎都可以使用。
- redo log 是物理日志,记录的是做了什么操作,binlog 是逻辑日志,记录的是这个语句的原始逻辑。
- redo log 是循环写的,空间固定会用完;binlog 可以追加写,“追加写”的意思是binlog 写到一定大小的文件后会自动切换到下一页,不会覆盖掉以前的数据。
update 语句执行时的内部流程:
- 引擎直接用树搜索找到这一行,如果这一行所在的数据页在内存中就直接返回,否则先从磁盘读入内存,然后再返回。
- 执行器拿到引擎返回的数据后执行修改操作,再调用引擎的接口写入这条数据。
3.引擎将这条数据更新到内存中,同时将更新语句记录到redo log 里面,此时redo log 处于prepare 状态。然后告诉执行器执行完成了可以随时提交事务。 - 执行器生成这个binlog 并将其写入到磁盘。
- 执行器调用引擎提供的接口提交事务,引擎把刚刚写入的redo log 改成提交状态,更新完成。
引擎和内存磁盘打交道,比如用搜索树查找数据,更新数据到内存中,更新redo log 日志的状态。
浅色的是InnoDB 内部执行的,深色的是在执行器中执行的。
两阶段提交
两阶段提交的目的:就是为了让binlog 日志和redo log 日志的逻辑一致。
两阶段提交:将redo log的写入拆成了两个步骤:prepare和commit,这就是"两阶段提交"。
怎样将日志恢复到半月内任意一秒的状态?
binlog 会记录所有的逻辑操作,并且采用“追加写”的形式。DBA 可能定期做数据的备份,这个“定期”取决于系统的重要性,可以是一天一备,也可以是一周一备。
为什么日志需要“两阶段提交?
由于redo log 和binlog 是两个独立的逻辑,如果不用两阶段提交数据库状态可能和它的日志恢复出来的库中的状态不一致。
不采用两阶段提交,先写redo log后写binlog;先写binlog后写redo log。恢复出来的数据和原数据会出现不一致的情况。