-
WAL(Write-Ahead Logging)机制
WAL 的全称是 Write-Ahead Logging,中文称预写式日志(日志先行),是一种数据安全写入机制。就是先写日志,然后再写入磁盘,这样既能提高性能又可以保证数据的安全性。Mysql中的redo log就是采用WAL机制
为什么使用WAL?
磁盘的写操作是随机IO,比较耗性能,所以如果把每一次的更新操作都先写入log中,那么就成了顺序写操作,实际更新操作由后台线程再根据log异步写入。这样对于client端,延迟就降低了。并且,由于顺序写入大概率是在一个磁盘块内,这样产生的io次数也大大降低。所以WAL的核心在于 将随机写转变为了顺序写,降低了客户端的延迟,提升了吞吐量
-
redo log 基本概念
InnoDB引擎对数据的更新,是先将更新记录写入redo log日志,然后会在系统空闲的时候或者是按照设定的更新策略再将日志中的内容更新到磁盘之中。这就是所谓的预写式技术(Write Ahead logging)。这种技术可以大大减少IO操作的频率,提升数据刷新的效率
redo log:被称作重做日志, 包括两部分:一个是内存中的日志缓冲(redo log buffer) ,另一个是磁盘上的日志文件(redo log file)
mysql 每执行一条 DML 语句,先将记录写入 redo log buffer ( redo日志记录的是事务对数据库做了哪些修改 ) 。后续某个时间点再一次性将多个操作记录写到 redo log file。当故障发生致使内存数据丢失后,InnoDB会在重启时,经过重放 redo,将Page恢复到崩溃之前的状态 通过Redo log可以实现事务的持久性
-
redo log数据落盘流程
将内存中的数据页持久化到磁盘,需要下面的两个流程来完成:
-
脏页落盘机制
脏页是指修改了Buffer Pool中的数据页后,导致了内存中的数据页和磁盘中的数据页不一致,这时就出现了脏页当进行数据页的修改操作时: 首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上。页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过一种称CheckPoint 的机制刷新回磁盘
checkpoint机制
思考一下这个场景:如果重做日志可以无限地增大,同时缓冲池也足够大,那么是不需要将缓冲池中页的新版本刷新回磁盘。因为当发生宕机时,完全可以通过重做日志来恢复整个数据库系统中的数据到宕机发生的时刻
checkpoint(检查点)技术主要解决以下几个问题
- 缩短数据库的恢复时间
- 缓冲池不够用时,将脏页刷新到磁盘
- 重做日志不可用时,刷新脏页
脏页落盘的时机 采用CheckPoint检查点机制 以下机制都可通过参数控制
-
redo log 持久化
缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统缓冲区( OS Buffer )。因此,redo log buffer 写入 redo log file 实际上是先写入 OS Cache,然后再通过系统调用 fsync() 将其刷到redo log file
Redo Buffer 持久化到 redo log 的策略, 可通过 Innodb_flush_log_at_trx_commit 设置:
一般建议选择取值2,因为 MySQL 挂了数据没有损失,整个服务器挂了才会损失1秒的事务提交数据
-
-
redo log日志格式
物理日志VS逻辑日志
-
物理日志: 记录的是每一个page页中具体存储的值是多少,在这个数据页上做了什么修改. 比 如: 某个事物将系统表空间中的第100个页面中偏移量为1000处的那个字节的值1改为2
-
逻辑日志: 记录的是每一个page页面中具体数据是怎么变动的,它会记录一个变动的过程或SQL语句的逻辑, 比如: 把一个page页中的一个数据从1改为2,再从2改为3,逻辑日志就会记录1->2,2->3这个数据变化的过程
redo日志属于物理日志, 只是记录一下事务对数据库做了哪些修改
-
-
redo log 写入机制
redo log buffer是用来缓存写入到redo log文件中的数据内容的,那么是不是每次redo log buffer产生内容就立即写入到磁盘进行持久化呢 ?
其实不需要的,就算在事务执行期间MySQL宕机了,redo log 缓冲区中的内容丢失了,也不会有损失,因为事务并没有提交(事务提交,必然写入日志完成)redo log 三种状态
- 存在于redo log buffer 内存区域中
- 向磁盘写入,但是没有真正写入磁盘,而是保存在文件系统缓存中
- 持久化到磁盘
如果事务没有提交的时候,redo log buffer中的部分日志有可能被持久化到磁盘吗 ?
触发真正的fsync写盘的场景- redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动写盘
- 并行的事务提交的时候,顺带将某个未提交的事务的redo log buffer 持久化到磁盘。因为redo log buffer 是共享的,因此一些正在执行中的事务的redo log信息也有可能被持久化到磁盘中
组提交
MySQL 为了优化磁盘持久化的开销,会有一个组提交(group commit)的机制每个InnDB存储引擎至少有1个重做日志文件组(group),每个文件组下至少有两个重做日志文件,默认的为 ib_logfile0 、 ib_logfile1
InnoDB 以环型方式(circular fashion)写入数据到重做日志文件,当文件满了的时候,会自动切换到日志文件2,当重做日志文件2也写满时,会再切换到重做日志文件1
write pos: 表示日志当前记录的位置,当ib_logfile_4写满后,会从ib_logfile_1从头开始记录check point: 表示将日志记录的修改写进磁盘,完成数据落盘,数据落盘后checkpoint会将日志上的相关记录擦除掉,即 write pos -> checkpoint 之间的部分是redo log空着的部分,用于记录新的记录, checkpoint -> write pos 之间是redo log 待落盘的数据修改记录
如果 write pos 追上 checkpoint,表示写满,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下