日志类型
MySQL主要有两种日志类型,一种是
物理日志
(记录在某个数据页上做了什么修改),一种是逻辑日志
(存储了逻辑SQL修改语句)。redo log
属于物理日志,binlog
和undo log
属于逻辑日志,其中物理日志的恢复速度远快于逻辑日志。
redo log
和undo log
都属于InnoDB
引擎层下的事务日志(transaction log)
。
重做日志 (redo log)
预写式技术 (Write Ahead logging, WAL)
InnoDB 引擎对数据更新,是先将更新记录写入到重做日志,在系统空闲时或者按照设定的更新策略再将日志中的内容更新到磁盘中,这就是
预写式技术 (Write Ahead logging, WAL)
,这种技术可以大大减少IO操作的频率,提升数据刷新的效率。
重做日志的策略
重做日志(redo log)是 InnoDB 引擎层的日志,用来记录事务操作引起数据的变化,记录的是数据页的物理修改,提供
前滚
操作,redo log 保证事务的持久性
。重做日志由两部分组成,一是内存中的重做日志缓冲区 (redo log buffer)
,因为重做日志缓冲区在内存中,所以它是易失的
,另一个就是在磁盘上的重做日志文件 (redo log file)
,它是持久的。
当我们在一个事务中尝试对数据进行修改时,它会先将数据从磁盘读入内存,并更新内存中缓存的数据,然后生成一条重做日志并写入重做日志缓存,当事务真正提交时,MySQL 会将重做日志缓存中的内容刷新到重做日志文件,再将内存中的数据更新到磁盘上。
值得注意的是,redo log 的大小是固定的,为了能够持续不断的对更新记录进行写入,在redo log日志中设置了两个标志位置,checkpoint
和write pos
。checkpoint
表示记录擦除的位置,write pos
表示记录写入的位置。当write pos
标志到了日志结尾时,会从结尾跳至日志头部循环写入,所以redo log的逻辑结构并不是线性的,可以看做一个圆周运动,逻辑结构见下图:
当write_pos
追上checkpoint
时,表示redo log日志已经写满。这时不能继续执行新的数据库更新语句,需要停下来先删除一些记录,执行checkpoint
规则腾出可写空间。
checkpoint规则: checkpoint触发后,将buffer中脏数据页和脏日志页都刷到磁盘。所谓的脏数据页就是指内存中未刷到磁盘的数据
redo log中最重要的概念就是缓冲池buffer pool
,这是在内存中分配的一个区域,包含了磁盘中部分数据页的映射,作为访问数据库的缓冲。当请求读取数据时,会先判断是否在缓冲池命中,如果未命中才会在磁盘上进行检索后放入缓冲池;当请求写入数据时,会先写入缓冲池,缓冲池中修改的数据会定期刷新到磁盘中。这一过程也被称之为刷脏 。
因此,当数据修改时,除了修改buffer pool
中的数据,还会在redo log中记录这次操作;当事务提交时,会根据redo log的记录对数据进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复,从而保证了事务的持久性,使得数据库获得crash-safe
能力。
回滚日志 (undo log)
回滚日志的作用就是对数据进行回滚。当事务对数据库进行修改,InnoDB引擎不仅会记录redo log,还会生成对应的undo log日志;如果事务执行失败或调用了rollback,导致事务需要回滚,就可以利用undo log中的信息将数据回滚到修改之前的状态。
但是undo log和redo log不一样,它属于逻辑日志。它对SQL语句执行相关的信息进行记录。当发生回滚时,InnoDB引擎会根据undo log日志中的记录做与之前相反的工作。比如对于每个数据插入操作(insert),回滚时会执行数据删除操作(delete);对于每个数据删除操作(delete),回滚时会执行数据插入操作(insert);对于每个数据更新操作(update),回滚时会执行一个相反的数据更新操作(update),把数据改回去。undo log有两个作用,一是提供
回滚
,二是实现MVCC
。
二进制日志 (binlog)
二进制日志binlog是服务层的日志,还被称为归档日志。binlog主要记录数据库的变化情况,内容包括数据库所有的更新操作。所有涉及数据变动的操作,都要记录进二进制日志中。因此有了binlog可以很方便的对数据进行复制和备份,因而也常用作主从库的同步。