InnoDB采用redolog机制保证事务更新的一致性和持久性。

深入浅出MySQL这本书没有介绍UndoLog,所以参考了其他的博客。

本文参考深入浅出MySQL书17.3章节。

 

当更新数据时,InnoDB内部的操作流程大致如下:

  1. 将数据读入InnoDB Buffer Pool,并对相关记录加上独占锁
  2. 将Undo信息写入undo表空间的回滚段中。
  3. 更改缓存页中的数据,并将更新记录写入redo buffer中。
  4. 提交时,根据innodb_flush_log_at_trx_commit的设置,用不同的方式将redo buffer中的更新记录刷新到InnoDB redo log file中,然后释放独占锁。
  5. 最后,后台I/O线程根据需要择机将缓存中更新过的数据刷新到磁盘文件中。

 

接下来我们根据这个流程,一步一步解释。

 

InnoDB Buffer Pool

它是一块连续的内存页面,用来存储访问过的数据,同时为数据块和索引块提供数据缓存。

innodb_buffer_pool参数用来定义InnoDB引擎buffer pool的大小,值越大,缓存命中率就越高。访问磁盘的I/O越少,性能也就越高,但是需要避免设置过大而导致页交换。

数据按照数据页的方式读取到buffer pool中,MySQL的数据页大小是16kb(操作系统的页是4kb)。

 

buffer pool 采用【LRU算法】管理buffer pool。

这个算法的思想其实跟内存管理是一样的,近期使用过的数据将来被访问的概率更高。所以常用的放在链表头,不常用的放在表尾。

简单LRU算法:

  • 新插入数据放在链表头
  • 缓存命中,二次访问数据提升到链表头
  • 淘汰数据从链表尾部淘汰。

 

LRU – 中点插入策略

假设我们将最近访问的数据直接放到表头,那么就可能导致这样的问题:有些数据只访问了一次,就直接放在了表头,很久才会刷新出去。

所以我们可以将LRU List分为young和old两部分(它们都在链表中,只是young在头部,old在尾部),分别代表新数据(常访问数据)和老数据(不常访问数据)。然后我们将最近访问的数据(假设它叫A)插入到young的表尾,或者说old的表头。经过一段时间后,随着访问量的增高,这个A可能会随着访问量的升高进入到young的头部,或者一直没人访问,被降到old的尾部,直至被淘汰。

将这个策略简化后可以理解为,将新数据插入在表中部,二次命中就提升到表头,这种方案比前面单纯的LRU就更先进一筹。

当这个数据A没有被二次访问的情况下,相比于插入到表头,插入到表中间会更快被淘汰。

 

更多LRU算法相关:

LRU算法拓展 与 LFU算法思想

 

UndoLog

UndoLog日志用于存放数据被修改前的值,假设事务修改表中id=2的行数据,将Name=”B”修改为Name=”B2″。

那么UndoLog就会用来存放Name=”B”的记录,如果事务出现异常,则使用UndoLog实现回滚操作,保证事务原子性。

事务的原子性:整个事务要么全部完成,要么失败回滚。

 

RedoLog

当数据库对数据做修改的时候,需要把数据页从磁盘读到buffer pool中,然后在buffer pool中进行修改。

那么这个时候buffer pool中的数据页就与磁盘上的数据页内容不一致,称buffer pool的数据页为dirty page 脏数据。

如果这个时候发生非正常的DB服务重启,那么这些数据还没在内存,并没有同步到磁盘文件中(注意,同步到磁盘文件是个随机IO),也就是会发生数据丢失,如果这个时候,能够在有一个文件,当buffer pool 中的data page变更结束后,把相应修改记录记录到这个文件(注意,记录日志是顺序IO),那么当DB服务发生crash的情况,恢复DB的时候,也可以根据这个文件的记录内容,重新应用到磁盘文件,数据保持一致。

这个文件就是RedoLog文件,用于记录数据修改后的内容,记录是顺序的。

 

记录的好处是:

  • 当缓存中的内容还没有刷新到磁盘,发生Crash重启后,可以通过RedoLog找到需要重新刷新到磁盘的数据。
  • buffer pool中的数据直接刷新到磁盘file,是随机IO,效率较差;而我们从redo log刷新则是顺序IO,可以提高事务提交的速度。

 

大致就是这么个情况咯。

【MySQL】数据更新与UndoLog、RedoLog
Tagged on:
0 0 vote
Article Rating
订阅
提醒
0 评论
Inline Feedbacks
View all comments