进入正题前,可以先简单介绍一下,MySQL的逻辑架构,
MySQL的逻辑架构大致可以分为三层:
- 第一层:处理客户端连接、授权认证,安全校验等。
- 第二层:服务器 server 层,负责对SQL解释、分析、优化、执行操作引擎等。
- 第三层:存储引擎,负责MySQL中数据的存储和提取。
我们要知道MySQL的服务器层是不管理事务的,事务是由存储引擎实现的,而MySQL中支持事务的存储引擎又属 InnoDB 使用的最为广泛,所以后续文中提到的存储引擎都以 InnoDB 为主。
而且,可以再简单介绍一下,MySQL数据更新流程,作为铺垫,具体如下图:
一、redo log(重做日志)
redo log 属于MySQL存储引擎InnoDB的事务日志。
MySQL的数据是存放在磁盘中的,每次读写数据都需做磁盘IO操作,如果并发场景下性能就会很差。为此MySQL提供了一个优化手段,引入缓存Buffer Pool。
这个缓存中包含了磁盘中部分数据页(page)的映射,以此来缓解数据库的磁盘压力。
当从数据库读数据时,首先从缓存中读取,如果缓存中没有,则从磁盘读取后放入缓存;
当向数据库写入数据时,先向缓存写入,此时缓存中的数据页数据变更,这个数据页称为脏页,BufferPool中修改完数据后会按照设定的更新策略,定期刷到磁盘中,这个过程称为刷脏页。
如何保证数据不丢失 ,实现高可靠,实现事务持久性 ?
如果刷脏页还未完成,可MySQL由于某些原因宕机重启,此时Buffer Pool中修改的数据还没有及时的刷到磁盘中,就会导致数据丢失,无法保证事务的持久性。为了解决这个问题引入了redo log,redo Log如其名侧重于重做!
它记录的是数据库中每个页的修改,而不是某一行或某几行修改成怎样,可以用来恢复提交后的物理数据页,且只能恢复到最后一次提交的位置。
redo log用到了WAL(Write-Ahead Logging)技术,这个技术的核心就在于修改记录前,一定要先写日志,并保证日志先落盘,才能算事务提交完成。
有了redo log再修改数据时,InnoDB引擎会把更新记录先写在redo log中,再修改Buffer Pool中的数据,当提交事务时,调用fsync把redo log刷入磁盘。至于缓存中更新的数据文件何时刷入磁盘,则由后台线程异步处理。
注意:此时redo log的事务状态是prepare,还未真正提交成功,要等bin log日志写入磁盘完成才会变更为commit,事务才算真正提交完成。
这样一来即使刷脏页之前MySQL意外宕机也没关系,只要在重启时解析redo log中的更改记录进行重放,重新刷盘即可。
redo log 大小固定
redo log采用固定大小,循环写入的格式,当redo log写满之后,重新从头开始如此循环写,形成一个环状。
那为什么要如此设计呢?
因为redo log记录的是数据页上的修改,如果Buffer Pool中数据页已经刷磁盘后,那这些记录就失效了,新日志会将这些失效的记录进行覆盖擦除。
上图中的write pos表示redo log当前记录的日志序列号LSN(log sequence number),写入还未刷盘,循环往后递增;
check point表示redo log中的修改记录已刷入磁盘后的LSN,循环往后递增,这个LSN之前的数