mysql事务持久化时宕机_MySQL中事务的持久性实现原理前⾔
说到数据库事务,⼤家脑⼦⾥⼀定很容易蹦出⼀堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等。
当然MySQL博⼤精深,⽂章疏漏之处在所难免,欢迎批评指正。
说明
MySQL的事务实现逻辑是位于引擎层的,并且不是所有的引擎都⽀持事务的,下⾯的说明都是以InnoDB引擎为基准。
InnoDB读写数据原理
在往下学习之前,我们需要先来了解下InnoDB是怎么来读写数据的。我们知道数据库的数据都是存放在磁盘中的,然后我们也知道磁盘I/O 的成本是很⼤的,如果每次读写数据都要访问磁盘,数据库的效率就会⾮常低。为了解决这个问题,InnoDB提供了 Buffer Pool 作为访问数据库数据的缓冲。
Buffer Pool 是位于内存的,包含了磁盘中部分数据页的映射。当需要读取数据时,InnoDB会⾸先尝试从Buffer Pool中读取,读取不到的话就会从磁盘读取后放⼊Buffer Pool;当写⼊数据时,会先写⼊Buffer Pmysql面试题acid
ool的页⾯,并把这样的页⾯标记为dirty,并放到专门的flush list上,这些修改的数据页会在后续某个时刻被刷新到磁盘中(这⼀过程称为刷脏,由其他后台线程负责) 。如下图所⽰:
这样设计的好处是可以把⼤量的磁盘I/O转成内存读写,并且把对⼀个页⾯的多次修改merge成⼀次I/O操作(刷脏⼀次刷⼊整个页⾯),避免每次读写操作都访问磁盘,从⽽⼤⼤提升了数据库的性能。
分数段switch语句流程图持久性定义
js数组与对象持久性是指事务⼀旦提交,它对数据库的改变就应该是永久性的,接下来的其他操作或故障不应该对本次事务的修改有任何影响。
通过前⾯的介绍,我们知道InnoDB使⽤ Buffer Pool 来提⾼读写的性能。但是 Buffer Pool 是在内存的,是易失性的,如果⼀个事务提交了事务后,MySQL突然宕机,且此时Buffer Pool中修改的数据还没有刷新到磁盘中的话,就会导致数据的丢失,事务的持久性就⽆法保证。mysql怎么删除存储过程
为了解决这个问题,InnoDB引⼊了 redo log来实现数据修改的持久化。当数据修改时,InnoDB除了修改Buffer Pool中的数据,还会在redo log 记录这次操作,并保证redo log早于对应的页⾯落盘(⼀般在事务提交的时候),也就是常说的WAL。若MySQL突然宕机了且还没有把数据刷回磁盘,重启后,MySQL会通过已经写⼊磁盘的redo log来恢复没有被刷新到磁盘的数据页。
实现原理:redo log
为了提⾼性能,和数据页类似,redo log 也包括两部分:⼀是内存中的⽇志缓冲(redo log buffer),该部分⽇志是易失性的;⼆是磁盘上的重做⽇志⽂件(redo log file),该部分⽇志是持久的。redo log是物理⽇志,记录的是数据库中物理页的情况 。
当数据发⽣修改时,InnoDB不仅会修改Buffer Pool中的数据,也会在redo log buffer记录这次操作;当事务提交时,会对redo log buffer进⾏刷盘,记录到redo log file中。如果MySQL宕机,重启时可以读取redo log file中的数据,对数据库进⾏恢复。这样就不需要每次提交事务都实时进⾏刷脏了。
写⼊过程
注意点:先修改Buffer Pool,后写 redo log buffer。
redo⽇志⽐数据页先写回磁盘:事务提交的时候,会把redo log buffer写⼊redo log file,写⼊成功才算提交成功(也有其他场景触发写⼊,这⾥就不展开了),⽽Buffer Pool的数据由后台线程在后续某个时刻写⼊磁盘。
刷脏的时候⼀定会保证对应的redo log已经落盘了,也即是所谓的WAL(预写式⽇志),否则会有数据丢失的可能性。
好处
事务提交的时候,写⼊redo log 相⽐于直接刷脏的好处主要有三点:刷脏是随机I/O,但写redo log 是顺序I/O,顺序I/O可⽐随机I/O快多了,不需要。
刷脏是以数据页(Page)为单位的,即使⼀个Page只有⼀点点修改也要整页写⼊;⽽redo log中只包含真正被修改的部分,数据量⾮常⼩,⽆效IO⼤⼤减少。
刷脏的时候可能要刷很多页的数据,⽆法保证原⼦性(例如只写了⼀部分数据就失败了),⽽redo log buffer 向 redo log file 写log block,是按512个字节,也就是⼀个扇区的⼤⼩进⾏写⼊,扇区是写⼊的最⼩单位,因此可以保证写⼊是必定成功的。
先写redo log还是先修改数据
⼀次DML可能涉及到数据的修改和redo log的记录,那它们的执⾏顺序是怎么样的呢?⽹上的⽂章有的说先修改数据,后记录redo log,有的说先记录redo log,后改数据,那真实的情况是如何呢?
⾸先通过上⾯的说明我们知道,redo log buffer在事务提交的时候就会写⼊redo log file的,⽽刷脏则是在后续的某个时刻,所以可以确定的是先记录redo log,后修改data page(WAL当然是⽇志先写啦)。
那接下来的问题就是先写redo log buffer还是先修改Buffer Pool了。要了解这个问题,我们先要了解InnoDB中,⼀次DML的执⾏过程是怎么样的。⼀次DML的执⾏过程涉及了数据的修改,加锁,解锁,redo log的记录和undo log的记录等,也是需要保证原⼦性的,⽽InnoDB通过MTR(Mini-transactions)来保证⼀次DML操作的原⼦性。网页模板插件
⾸先来看MTR的定义:An internal phase of InnoDB processing, when making changes at the physical level to internal data structures during DML operations. A Mini-transactions (mtr) has no notion of rollback; multiple Mini-transactionss can occur within a single transaction. Mini-transactionss write information to the redo log that is used during crash recovery. A Mini-transactions can also happen outside the context of a regular transaction, for example during purge processing by background threads.
MTR 是⼀个短原⼦操作,不能回滚,因为它本⾝就是原⼦的。数据页的变更必须通过MTR,MTR 会把DML操作对数据页的修改记录到redo log⾥。
int1等于多少下⾯来简单看下MTR的过程:MTR初始化的时候会初始化⼀份 mtr_buf
当修改数据时,在对内存Buffer Pool中的页⾯进⾏修改的同时,还会⽣成redo log record,保存在mtr_buf中。
在执⾏mtr_commit函数提交本MTR的时候,会将mtr_buf中的redo log record更新到redo log buffer中,同时将脏页添加到flush list,供后续刷脏使⽤。在log buffer中,每接收到496字节的log record,就将这组log record包装⼀个12字节的block header和⼀个4字节的block tailer,成为⼀个512字节的log block,⽅便刷盘的时候对齐512字节刷盘。
由此可见,InnoDB是先修改Buffer Pool,后写redo log buffer的。
恢复数据的过程
在任何情况下,InnoDB启动时都会尝试执⾏recovery操作。在恢复过程中,需要redo log参与,⽽如果还开启了binlog,那就还需要binlog、undo log的参与。因为有可能数据已经写⼊binlog了,但是redo log还没有刷盘的时候数据库就奔溃了(事务是InnoDB引擎的特性,修改了数据不⼀定提交了,⽽binlog是MySQL服务层的特性,修改数据就会记录了),这时候就需要redo log,binlog和undo log三者的参与来判断是否有还没提交的事务,未提交的事务进⾏回滚或者提交操作。
下⾯来简单说下仅利⽤redo log恢复数据的过程:启动InnoDB时,到最近⼀次Checkpoint的位置,利⽤Checkpoint LSN去⼤于该LSN的redo log进⾏⽇志恢复。
如果中间恢复失败了也没影响,再次恢复的时候还是从上次保存成功的Checkpoint的位置继续恢复。
Recover过程:故障恢复包含三个阶段:Analysis,Redo和Undo。Analysis阶段的任务主要是利⽤Checkpoint及Log中的信息确认后续Redo和Undo阶段的操作范围,通过Log修正Checkpoint中记录的Dirty Page集合信息,并⽤其中涉及最⼩的LSN位置作为下⼀步Redo的开始位置RedoLSN。同时修正Checkpoint中记录的活跃事务集合(未提交事务),作为Undo过程的回滚对象;Redo阶段从Analysis获得的RedoLSN出发,重放所有的Log中的Redo内容,注意这⾥也包含了未Commit事务;最后Undo阶段对所有未提交事务利⽤Undo信息进⾏回滚,通过Log的PrevLSN 可以顺序到事务所有需要回滚的修改。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。