MySQL 重做日志 redo log

专栏持续更新中:MySQL详解

在事务的ACID特性中,原子性(A)、一致性(C)、持久性(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:被称为物理日志,用于记录事务操作的变化,确保事务的持久性。事务begin就开始记录,无论事务是否commit都会记录,若异常发生,下一次mysqld再启动时,会使用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,就是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大致结构如图所示:

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

buffer pool默认大小为128M(MySQL 5.7)

二、缓存、磁盘结构

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

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

是不是commit的时候,buffer poll里面的脏数据(数据有被修改)同步被写入磁盘?

并不需要等commit的时候才开始。事务可能修改的数据量比较大,而缓存容量有限,对于buffer poll缓存的数据,会有专门的线程在合适的时间,往磁盘上去刷新,如果出现掉电,下一次MySQL启动后,会根据redo log里面记录的数据,对数据进行恢复。所以当事务commit后,最重要的是redo log要写成功

undo log本身也是记录在redo log中

undo log支持事务回滚,也不是一瞬间就能完整,最终要修改的也是磁盘上的数据,回滚过程也会出现异常,下次服务重启时,需要使用undo log重新回滚,所以undo log要记录在redo log里面。事务commit成功或者rollback成功,对于底层,都是成功的把操作写到磁盘上的redo log里面

什么是真正的事务commit成功?

不是把数据全部刷到磁盘,而是把记录事务完整操作的redo log从log buffer写入磁盘,再把被修改数据的状态置为commit才算是实现了事务commit成功。此时虽然数据还在buffer poll,但只要我们的redo log保存完整,数据就可以恢复,会有专门的线程去负责把buffer poll里的数据写入磁盘

什么叫事务commit成功?(和上面的问题一样)

事务执行commit命令后,mysqld将记录了数据修改的Log Buffer写入磁盘上的redo log,然后将这部分数据的状态修改为commit,写完redo log后才算是事务提交成功,MySQL Server需要保持commit状态的数据的持久性。如果写redo log失败,数据的状态还是prepare,尽管事务执行了commit命令,这依然不算commit成功

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

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

相关推荐
·薯条大王26 分钟前
MySQL联合查询
数据库·mysql
战族狼魂1 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
杉之2 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
morris1312 小时前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
hycccccch3 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
bobz9653 小时前
k8s 怎么提供虚拟机更好
后端
这个懒人3 小时前
深入解析Translog机制:Elasticsearch的数据守护者
数据库·elasticsearch·nosql·translog
Yan-英杰4 小时前
【百日精通JAVA | SQL篇 | 第二篇】数据库操作
服务器·数据库·sql
bobz9654 小时前
nova compute 如何创建 ovs 端口
后端
用键盘当武器的秋刀鱼4 小时前
springBoot统一响应类型3.5.1版本
java·spring boot·后端