为了实现事务的原子性和持久性,mysql引入了undo和redo日志。本文讲解下undo和redo的概念,以及mysql如何利用undo和redo进行异常宕机恢复。
undo 日志
undo日志记录的是修改前的值。
比如:
事务A要将字段age的值由原来的1修改为2,要将name的值由原来的Alice修改为Bob,undo日志记录的是:
如果在上表第三步之前数据库挂了,则最终数据和日志均为原数据;如果第三步及以后出现异常,则undo已经记录了原来的值,则可以利用undo日志将数据恢复为原数据。
在事务提交之后,undo不会被马上删除,而是放入待删除队列,由purge线程来判断是否删除和处理。
在mysql5.6之前,undo只存在于共享表空间中,之后的版本中,可以配置为独立的文件。
undo内部默认128个回滚段槽(rseg slot),每个rseg slot内部有1024个回滚段(rollback segment)。其中:
▪ slot0——共1个,预留给系统表空间
▪ slot1-slot31——共31个,预留给临时表空间
▪ slot32-slot127——共96个,预留给undo独立表空间
由于undo日志会被清理掉,不能保证事务的持久性,因此引入redo日志来保证事务的持久性。
redo日志
redo日志记录的是修改后最新的数据和冗余的undo日志。
比如:
事务B要将字段age的值由原来的1修改为2,要将name的值由原来的Alice修改为Bob,redo日志记录的是:
其中,redo日志必须先于数据写入磁盘,因为如果不这样,在数据提交之后再写redo日志,一旦redo日志的写入过程出现异常,将无法保证持久性。
记录redo日志时,先记入redo log buffer,最后再一起写入磁盘,这样可以减少IO,提升性能。
未提交的事务和回滚了的事务也会计入redo日志。
如果上面事务B回滚(当做新的事务C),则redo记录的是:
mysql的恢复策略
mysql的恢复策略是:恢复时,先根据redo重做所有事务(包括未提交和回滚了的),再根据undo回滚未提交的事务。
如上,如果事务B异常未提交事务就宕机,恢复时,先根据redo日志将数据恢复为age=2&name=Bob,然后根据undo记录的age=1&name=Alice将数据恢复如初。
如果事务C异常未提交事务就宕机,恢复时,根据redo日志,可以直接恢复至age=1&name=Alice的初始状态。
redo日志会随着时间推移而越来越大,为了提升redo的恢复性能,引入了checkpoint机制,在恢复的时候,只需要从checkpoint的位置往后恢复即可。
—END—
自由,
是因为自己真的有方向。
领取专属 10元无门槛券
私享最新 技术干货