首先mysql的自动故障恢复在5.7的版本中引入,叫法很多,CR、CS、CSR,我们这里就ACSR(Auto Crash Safey Recovery)自动的故障安全恢复
这里我们先以一个示例来描述一个完整的事务工作过程:
1、执行begin;开始一个事务
2、执行update t1 set a=123 where id=1;
3、将数据页拉到内存buffer\_pool
4、将原数据页信息记录到log\_buffer
5、log\_buffer中原数据页日志写到os的undo中并最终落盘到undo.log
6、修改数据页
7、修改的数据页信息记录在log\_buffer中
8、执行commit;提交该事务
9、log\_buffer中原数据页的日志和修改后的数据页日志写到os的redo中并最终落盘到redo.log
10、数据页写回磁盘
当然过程7还包含2PC,就不详细说明了。
以上就是一个事务提交的整个过程了,从而引出mysql的ACSR
整个过程用户在客户端一共需要执行3次命令(这里不谈论自动提交、隐式提交的情况),begin;、update t1 set a=123 where id=1;、commit;
大家思考一个问题,假设用户在执行了过程2后mysql就宕机了,会发生什么?
由于用户还没有执行commit,该语句一定不会提交成功,那么现在mysql恢复后他内部会做什么呢
ACSR(回滚):对比磁盘数据页、undo和redo的LSN号,如果有缺失,将数据页和undo分别拉回内存,回滚数据,并更新LSN号。简单的用时间线来说就是:0是磁盘数据的序号,1是undo.log的序号,0是redo.log的序号(因为没有执行commit所以redo的序列号同磁盘的序列号小于undo的序列号),当mysql对比三者的序列号后会发现update t1 set a=123 where id=1;还没有commit,所以会回滚该语句,a并没有改成123。
同理,假设用户在执行了过程8后瞬间宕机了呢
ACSR(前滚):对比磁盘数据页、undo和redo的LSN号,如果有缺失,将数据页和redo分别拉回buffer_pool和log_buffer重构脏页,写回磁盘并更新LSN号。还是简单的用时间线来说:0是磁盘数据的序号,1是undo.log的序号,2是redo.log的序号(因为用户已经执行了commit所以redo的序列号>undo的序列号>磁盘的序列号),当mysql对比三者的序列号后会发现update t1 set a=123 where id=1;已经commit了但是数据还没有落盘,所以会前滚该语句,a改成123。
最后还有个彩蛋:
假设在执行过程10的过程中数据库宕机了会发生什么呢?
DWB(Double write buffer)(双写机制),此时通过redo前滚难度较大(因为部分数据落盘了部分数据未落盘)所以会通过DWB来恢复数据。在正常的数据页写回磁盘前,会先写到DWB中,然后DWB落盘(日志文件),最后DWB落盘(数据磁盘存储),从而保证磁盘数据的完整性。
最后一次更新于2024-06-05