0

MySQL 自动的故障安全恢复详解(ACSR)

 2 years ago
source link: https://blog.51cto.com/u_13874232/5156952
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

MySQL 自动的故障安全恢复详解(ACSR)

原创

进击的CJR 2022-03-29 13:18:38 ©著作权

文章标签 数据 mysql 回滚 前滚 文章分类 MySQL 数据库 阅读数346

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

在一行数据被更新的时候

MySQL 自动的故障安全恢复详解(ACSR)_mysql

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对数据页进行重做。

MySQL 自动的故障安全恢复详解(ACSR)_数据_02

如果在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服务正常启动
  • 收藏
  • 评论
  • 分享
  • 举报

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK