当前位置: 首页 > 科技观察

超详细的MySQL数据库InnoDB崩溃恢复机制总结

时间:2023-03-19 00:07:25 科技观察

概述不会半途而废,需要数据库日志和完整的崩溃恢复机制来保证。下面简单介绍一下InnoDB的崩溃恢复过程。相关概念lsn:可以理解为自数据库创建以来产生的重做日志量。值越大,表示数据库的更新越多,也可以理解为更新的时刻。另外,每个数据页上还有一个lsn,表示最后一次修改时的lsn。值越大,修改越晚。比如数据页A的lsn为100,数据页B的lsn为200,checkpointlsn为150,系统lsn为300,说明当前系统已经更新到300,数据页少了超过150已经刷入磁盘,所以数据A页的最新数据肯定在磁盘上,但数据B页不一定,它可能还在内存中。重做日志:现代数据库需要写入重做日志。比如修改一条数据,先写入redologs,再写入数据。写入重做日志后,直接返回成功给客户端。这样一来,虽然以前看起来磁盘是写了一次,但是由于随机写入磁盘(writedata)变成了顺序写入(writeredolog),所以性能得到了很大的提升。当数据库挂了,通过扫描redolog,可以找出没有被flush的数据页(在crash之前,数据页可能只是在内存中被修改,但是还没有来得及写入到磁盘),以确保数据不丢失。Undolog:数据库也提供了类似undo的功能。当你发现自己修改了一些数据不正确时,可以使用回滚命令回滚之前的操作。该功能需要undologs支持。另外,现代关系型数据库为了提高并发性(读取同一条记录,不同线程不冲突,读和写读写不冲突,只有同时写冲突),实现了类似MVCC的机制。在InnoDB中,这也依赖于undolog。为了实现统一管理,与redolog不同,undolog在BufferPool中有对应的数据页,与普通数据页一起管理。根据LRU规则,它们也会从内存中淘汰,稍后再从磁盘中读取。和普通数据页一样,undo页的修改也需要先写入redolog。Checkpoint:英文名称为checkpoint。为了提高数据库的性能,每次修改内存后,数据页都不会刷新到磁盘。Checkpoint之前的数据页保证放在磁盘上,所以之前的日志是没有用的(因为InnoDBredolog日志是回收的,这时候这部分日志可以被覆盖),Checkpoint之后的数据页可能放在磁盘上,也有可能没有写入磁盘,所以在crash恢复的时候还是需要用到checkpoint之后的log。InnoDB会根据脏页的刷新周期性的推进检查点,从而减少数据库崩溃恢复的时间。检查点信息位于第一个日志文件的头部。崩溃恢复:用户修改数据并收到成功消息。但是,对于数据库来说,此时修改的数据可能还没有放到磁盘上。如果此时数据库挂了,重启后,数据库需要将这些修改过的数据捞出来重写到磁盘,以保证用户的数据不丢失。这个从日志中提取数据的过程是崩溃恢复的主要任务,也可以称为数据库前滚。当然,在崩溃恢复中,还需要回滚未提交的事务,提交未提交的事务。由于回滚操作需要undologs的支持,undologs的完整性和可靠性需要redologs来保证,所以crashrecovery先进行redorollforward,然后undorollback。数据库崩溃恢复过程下面我们来看一下数据库崩溃恢复过程。整个过程在引擎初始化阶段(innobase_init)完成,其中最重要的函数是innobase_start_or_create_for_mysql,innodb通过这个函数完成创建和初始化,包括崩溃恢复。首先介绍一下数据库的前滚。crashrecovery相关参数分析1.innodb_fast_shutdown:innodb_fast_shutdown=0。意思是当MySQL关闭时,执行慢速关闭,不仅包括logflushing和datapageflushing,还包括datapurge,ibufmerge,bufferpooldump,以及lazytabledropoperations(如果有未完成的操作,即使执行了droptable并返回成功,也可能不会立即删除表)。innodb_fast_shutdown=1。这是默认值,这意味着当MySQL关闭时,只有日志和数据被刷新。innodb_fast_shutdown=2。这意味着当它关闭时,只有日志被刷新,其他什么都没有做,就好像MySQL崩溃了一样。该参数的值越大,MySQL的关机速度越快,但启动速度越慢,相当于把关机时需要做的工作搬到了崩溃恢复上。另外,如果要升级MySQL,建议使用第一种方法进行cleanshutdown。2、参数innodb_force_recovery主要用来控制InnoDB在启动时做什么工作。值越大,做的工作越少,越容易上手,但数据不一致的风险也越大。当MySQL因为一些不可控的原因无法启动时,可以设置这个参数,从1开始逐渐增加,直到MySQL启动,然后使用SELECTINTOOUTFILE导出数据,尽量减少数据丢失。innodb_force_recovery=0,这是默认参数,它会在启动时做所有的事情,包括redologapplication,undologrollback,启动后台master和purgethreads,以及ibufmerge。检测到数据页损坏。如果在系统表空间,会crash,在用户表空间,会显示错误日志。innodb_force_recovery=1。如果检测到数据页损坏,则不会崩溃或报错(buf_page_io_complete),启动时也不会校验表空间的第一个数据页(fil_check_first_page)的正确性,继续执行崩溃恢复如果无法访问表空间。(fil_open_single_table_tablespace,fil_load_single_table_tablespace),ddl操作无法执行(check_if_supported_inplace_alter),数据库也无法执行写操作(row_insert_for_mysql,row_update_for_mysql等),所有prepare事务也会回滚(trx_resurrect_insert,trx_resurrect_update_inplace_inprepar)。这个选项仍然很常用。数据页可能损坏,因为磁盘坏了。设置为1保证数据库正常启动。innodb_force_recovery=2。除了设置1后的操作不会运行外,后台的master和purge线程不会启动(srv_master_thread、srv_purge_coordinator_thread等),当你发现因为这两个线程导致数据库无法启动时,可以设置.innodb_force_recovery=3。除了设置2之后的操作不会运行,不会执行undo回滚数据库,但仍然会扫描回滚段,仍然会创建undo链表(trx_sys_init_at_db_start)。srv_read_only_mode将被打开。innodb_force_recovery=4。除了设置3之后的操作不会运行外,ibuf的操作不会运行(ibuf_merge_or_delete_for_page),表信息统计的线程也不会运行(因为坏的索引页会导致数据库崩溃)(info_low,dict_stats_update,ETC。)。从这个选项开始,以后的所有选项都会损坏数据,慎用。innodb_force_recovery=5。除了设置4之后的操作不会运行外,不会扫描回滚段(recv_recovery_rollback_active),也不会创建undo链表。这个主要用在undolog损坏的时候。innodb_force_recovery=6。除了设置5之后的操作不会运行外,不会执行数据库前滚操作,包括解析和应用(recv_recovery_from_checkpoint_start_func)。总结InnoDB实现了完善的崩溃恢复机制,保证数据库在任何状态下(包括崩溃恢复状态下)都能正常恢复,这是与文件系统最大的区别。