MySQL重做日志 redo log

一、引入redo log

在事务的ACID特性中,原子性(A)、一致性©、持久性(D)由undo log和redo log实现,隔离性(I)由锁+MVCC实现

undo log:事务还没有commit,中途执行异常,可以使用undo log把数据恢复到事务执行前的状态,确保事务的原子性

redo log:事务commit成功,由于更新磁盘数据需要一段时间,此时若发生异常,可以使用redo log重新执行这一事务的SQL,确保事务的持久性(只要事务commit成功,不管发生什么异常事件,只要下一次MySQL服务正常进行,那上一次commit的数据一定要恢复回来)

二、redo log概念

redo log:重做日志/物理日志,用来记录事务操作的变化,记录的就是最终修改后的按页面存储的数据页,直接存数据最终的状态,用于确保事务的持久性

undo log:被称为逻辑日志,存储的是具体的相应的SQL语句。如果现在执行的是insert,回滚的时候就执行delete;如果现在执行的update,就把原来的旧值再update回来

redo log默认放在/var/lib/mysql
在这里插入图片描述
redo log是在事务begin时就开始记录(并不是事务commit时才记录,因为整个事务做的操作可能很多,如果在commit的时候才写redo log,此时一旦发生异常,redo log还没写,这就太晚了,无法确保事务的持久性),不管事务是否提交都会记录下来,在异常发生时(如数据持久化过程中掉电),InnoDB会使用redo log恢复到掉电前的时刻,保证数据的完整性

innodb_log_buffer_size默认是16M(MySQL 5.7),就是redo log缓冲区的大小,它随着事务开始,就开始写redo log,如果事务比较大,为了避免事务执行过程中花费过多磁盘IO,可以设置比较大的redo log缓存,节省磁盘IO。往磁盘上刷是有刷新的时机,达到时机就花费磁盘IO,如果buffer比较大,会更慢的达到刷新的时机,效率更高
在这里插入图片描述
InnoDB修改操作数据,不是直接修改磁盘上的数据,实际只是修改Buffer Pool中的数据。InnoDB总是先把Buffer Pool中的数据改变记录到redo log中,用来进行崩溃后的数据恢复。 优先记录redo log,然后再找时机慢慢的将Buffer Pool中的脏数据刷新到磁盘上。

innodb_log_group_home_dir指定的目录下的两个文件:ib_logfile0,ib_logfile1,该文件被称作重做日志

buffer pool缓存池: 可存放索引缓存、数据缓存等,可加速读写,直接操作数据页,写redo log修改就算完成,有专门的线程去做把buffer pool中的dirty page写入磁盘

buffer pool默认大小为134M(MySQL 5.7)
在这里插入图片描述
缓存结构:
在这里插入图片描述

事务读取,修改都是优先操作缓存池中的数据。在实际项目中,mysqld会单独的跑在一个机器上,可以分配大量的内存专门做InnoDB的buffer pool,加快CRUD

三、磁盘、缓存结构

在这里插入图片描述

当我们做数据更新、数据操作的时候,事务开始以后,随着数据执行相应的一些sql,对于数据最终的更改都是先记录在redo log上的,对于数据、索引的修改都是记录在Buffer Pool里面。

当事务commit的时候,在关系图上的操作就是把InnoDB Log Buffer的内容写入磁盘,写成功的话,在磁盘上的redo log会记录状态——commit,如果没有写成功或者写完,则记录状态——prepare

log在写入磁盘的过程中也有可能发生异常,断电等问题,导致在写redo log的时候没有写完(这相当于事务没有commit成功),此时MySQL下次在恢复的时候就没有必要考虑这个事务的完整性,因为状态并不是commit,都写入磁盘上才表示redo log写成功,状态才变成commit。状态变成commit后需要维护事务的ACID特性。

  1. 是不是commit的时候,buffer poll里面的脏数据(数据有被修改)才被写入磁盘?
    并不需要等commit的时候才开始。事务可能修改的数据量比较大,而缓存容量有限,对于buffer poll缓存的数据,会有专门的线程在合适的时间,往磁盘上去刷新,如果出现掉电,下一次MySQL启动后,会根据redo log里面记录的数据,对数据进行恢复。
  2. undo log本身也是记录在redo log中
    undo log支持事务回滚,也不是一瞬间就能完整,最终要修改的也是磁盘上的数据,为防止回滚过程中出现异常,所以undo log要记录在redo log里面。事务commit成功或者rollback成功,对于底层,都是成功的把操作写到redo log里面。
  3. 什么是真正的commit成功?
    不是把数据全部刷到磁盘,而是把记录事务完整操作的redo log从log buffer写入磁盘,再把被修改数据的状态置为commit才算是实现了事务commit成功。此时虽然数据还在buffer poll,但只要我们的redo log保存完整,数据就可以恢复,会有专门的线程去负责把buffer poll里的数据写入磁盘,数据刷新到磁盘过程中,出现掉电等异常情况,下一次mysqld服务器重启后,会根据redo log里面记录的数据。进行数据恢复。

事务进行操作的时候,永远是先写redo log,然后才是写buffer pool;事务成功commit,就是要保证redo log完整记录到磁盘上

至于表数据的更改,buffer pool的脏数据页是不是刷新到磁盘上,我们根本不用担心,只要redo log完整的写到磁盘上,我们可以随时通过redo log重做日志来恢复事务成功commit的数据状态

数据库最重要的是日志,而不是数据

猜你喜欢

转载自blog.csdn.net/qq_41721746/article/details/125350116