黄东旭关于基础软件产品价值的思考
753
2023-07-02
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:被称为物理日志,记录的就是最终修改后的按页面存储的数据页,直接存数据最终的状态,用于确保事务的持久性
逻辑日志又称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默认大小为134M(MySQL 5.7)
大致结构如图所示:
事务读取,修改都是优先操作缓存池中的数据。在实际项目中,mysqld会单独的跑在一个机器上,可以分配大量的内存专门做InnoDB的buffer pool,加快CRUD
二、缓存、磁盘结构
当事务commit的时候,在关系图上的操作就是把InnoDB Log Buffer的内容写入磁盘,写成功的话,在磁盘上的redo log会记录状态——commit,如果没有写成功或者写完,则记录状态——prepare
log在写入磁盘的过程中也有可能发生异常,断电等问题,导致在写redo log的时候没有写完(这相当于事务没有commit成功),此时MySQL下次在恢复的时候就没有必要考虑这个事务的完整性,因为状态并不是commit,都写入磁盘上才表示redo log写成功,状态才变成commit。状态变成commit后需要维护事务的ACID特性。
是不是commit的时候,buffer poll里面的脏数据(数据有被修改)才被写入磁盘?
并不需要等commit的时候才开始。事务可能修改的数据量比较大,而缓存容量有限,对于buffer poll缓存的数据,会有专门的线程在合适的时间,往磁盘上去刷新,如果出现掉电,下一次MySQL启动后,会根据redo log里面记录的数据,对数据进行恢复。
undo log本身也是记录在redo log中
undo log支持事务回滚,也不是一瞬间就能完整,最终要修改的也是磁盘上的数据,为防止回滚过程中出现异常,所以undo log要记录在redo log里面。对于底层而言,在成功地将操作写入redo log后,无论事务是成功提交(commit)还是成功回滚(rollback),都被认为是成功的。
什么是真正的事务commit成功?
不是把数据全部刷到磁盘,而是把记录事务完整操作的redo log从log buffer写入磁盘,再把被修改数据的状态置为commit才算是实现了事务commit成功。此时虽然数据还在buffer poll,但只要我们的redo log保存完整,数据就可以恢复,会有专门的线程去负责把buffer poll里的数据写入磁盘
事务进行操作的时候,永远是先写redo log,然后才是写buffer pool;事务成功commit,就是要保证redo log完整记录到磁盘上
至于表数据的更改,buffer pool的脏数据页是不是刷新到磁盘上,我们根本不用担心,只要redo log完整的写到磁盘上,我们可以随时通过redo log重做日志来恢复事务成功commit的数据状态(数据库最重要的是日志,而不是数据)
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。