绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
MySQL 自动的故障安全恢复详解(ACSR)
2022-03-02 16:12:17

ACSR(Auto Crash Safey Recovery)自动的故障安全恢复

更新操作

在一行数据被更新时:

1、在使用BEGIN开启事务时,会先给.ibd文件中分配一个TXID号和LSN号,假设为tx_01与lsn1001;

2、在UPDATE执行时,MySQL会找到需更新数据的数据页,并将其内容加载到data buffer pool中,由DBWR(double write)线程记录变更数据页的内容,并且记录好TXID和更新LSN号,此时将产生脏页与脏数据;

3、使用LOGBWR(log double write)线程,将更新前的数据页变化内容与TXID号以及LSN号记录到undo log buffer中;

4、使用LOGBWR(log double write)线程,将更新后的数据页变化内容与TXID号以及LSN号记录到redo log buffer中。

现在,基于WAL原则为了应对用户进行ROLLBACK操作,LOGBWR(log double write)线程会将undo log buffer中的内容全部写入到undo_log即ibdata1(MySQL5.7版本undo_log仍然存在于共享表空间中)文件中。

COMMIT操作

现在我们基于上面BEGIN后发生的情况执行COMMIT操作,内部会做以下的3件事:

1、执行COMMIT操作,基于WAL原则,LOGBWR线程会先将redo log buffer中记录的日志信息写入redo_log文件中,在日志信息完全写入redo_log即ib_logfile文件后,会对该日志打上COMMIT的标志;

2、触发CKPT,将内存数据页更新到磁盘中,并且更新磁盘数据页文件userInfo.ibd中原有的LSN号,让其与redo_log文件中的LSN号保持一致;

3、清空内存undo log buffer、data buffer pool、redo log buffer以及磁盘上undo_log中的数据。

可以看到整个事务提交的过程是先写日志,再落盘写数据。

其实redo log buffer将数据刷新到redo_log文件中的策略除开自己手动执行COMMIT外还有另一种情况。

在多任务时,其他线程COMMIT操作也可能会导致整个redo log buffer的刷新,刷新的redo_log文件中会对本线程提交的事务打上NOCOMMIT的标记。

其实这种现象取决于data buffer pool中存储的数据量占据data buffer pool总量,一般来说如果占据到70%左右就会触发该现象,我们可以对其进行手动设置,但一般来说保持默认值即可。

回滚

现在我们基于上面BEGIN后发生的情况执行ROLLBACK操作,内部会做以下2件事:

1、执行ROLLBACK操作,LOGBWR线程会将undo log buffer中的数据重写回到data buffer pool中,并且会把内存脏页数据恢复到开始的值,然后对LSN号进行回滚更正;

2、清空内存undo log buffer、redo log buffer以及磁盘上undo_log中的数据。

前滚

MySQL : 在启动时,必须保证redo日志文件和数据文件LSN必须一致, 如果不一致就会触发CSR,终保证一致。

情况一:

我们做了一个事务,begin;update;commit。

1、begin时,会立即分配一个TXID=tx_01.

2、update时,会将需要修改的数据页(dp_01,LSN=1001),加载到data buffer中;

3、DBWR线程,会进行dp_01数据页修改更新,并更新LSN=1002;

4、LOGBWR日志写线程,会将dp_01数据页的变化+LSN+TXID存储到redobuffer;

5、执行commit时,LGWR日志写线程会将redobuffer信息写入redolog日志文件中,基于WAL原则;

在日志完全写入磁盘后,commit命令才执行成功(会将此日志打上commit标记);

6、假如此时宕机,内存脏页没有来得及写入磁盘,内存数据全部丢失;

7、MySQL再次重启时,必须要redolog和磁盘数据页的LSN是一致的,但是此时dp_01、TXID=tx_01磁盘是LSN=101、dp_01、TXID=tx_01、redolog中LSN=102;

MySQL此时无法正常启动,MySQL触发CSR。在内存追平LSN号,触发ckpt,将内存数据页更新到磁盘,从而保证磁盘数据页和redolog LSN一致,这时MySQL正常启动。

以上的工作过程,我们把它称之为基于REDO的"前滚操作"。

Log sequence number: 当前系统大的LSN号;

log flushed up to:当前已经写入redo日志文件的LSN;

pages flushed up to:已经将更改写入脏页的lsn号;

Last checkpoint at就是系统后一次刷新buffer pool脏中页数据到磁盘的checkpoint。

以上4个LSN是递减的,即:LSN1>=LSN2>=LSN3>=LSN4。

比对redo的LSN和数据页的LSN,如果数据页的LSN比redo小,那么就需要通过redo对数据页进行重做。

前滚回滚

如果在COMMIT操作过程前发生了宕机,此时内存中的数据会全部丢失,但是恰好宕机前一秒由于其他线程的COMMIT操作导致了整个redo log buffer的自动刷新,此时redo_log文件中已经写入了刚刚本线程操作事务的TXID号以及LSN号,且标记此次操作是NOCOMMIT状态的情况下重启mysqld.service服务时,将会产生如下情况:

1、重启mysqld.service服务,发现redo_log中记录的LSN号和ibd文件中记录的LSN号不一致,将触发CSR自动故障恢复机制的个阶段,前滚操作开始;

2、通过redo_log文件中的变更记录日志,在内存数据页中恢复更改的数据;

3、发现redo_log文件中的事务标记是NOCOMMIT,将触发CSR自动故障恢复的第二个阶段,回滚操作开始;

4、通过undo log文件中的信息记录,在内存数据页中对前滚数据进行更改;

5、使用LOGBWR线程,将更新的数据页变化信息与TXID以及LSN号记录到redo log buffer中;

6、此时LOGBWR线程会先将redo log buffer中记录的信息写入到redo_log文件中,在日志信息完全写入log file即ib_logfile文件后,会对该日志打上COMMIT标记;

7、触发CKPT,将内存数据页更新到磁盘文件ibd中;

8、回滚工作完成,redo_log中记录的LSN号与ibd中记录的LSN号一致,mysqld.service服务正常启动。

以上文章来源于公众号-数据和云 ,作者陈家睿  
分享好友

分享这个小栈给你的朋友们,一起进步吧。

MySQL大本营
创建时间:2019-04-18 16:52:37
MySQL大本营是MySQL爱好者交流的社区。关注:MySQL实战,MySQL高性能,MySQL架构实战,MySQL DBA职业发展。MySQL大本营旨在创造一个MySQL社区交流环境。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • coolriver
    栈主

小栈成员

查看更多
  • 小雨滴
  • hwayw
  • 栈栈
  • 老七
戳我,来吐槽~