Mysql技术内幕InnoDB存储引擎读书笔记--《二》InnoDB存储引擎

来源:互联网 发布:5357端口是什么 编辑:程序博客网 时间:2024/05/29 12:20

2.1InnoDB存储引擎概述

InnoDB存储引擎是第一个完整支持ACID事务的Mysql存储引擎,行锁设计,支持MVCC,提供一致性非锁定读,支持外键,被设计用来最有效利用内存和CPU。

2.2InnoDB体系架构

InnoDB存储引擎具备一个大内存池,负责如下工作:

  • 维护所有进程/线程需要访问的多个内部数据结构
  • 缓存磁盘上的数据,方便快速的读取,并且在对磁盘文件的数据进行修改之前在这里缓存
  • 重做日志(redo log )缓冲

2.2.1后台线程

默认情况下,InnoDB存储引擎的后台线程有7个——4个I/O thread,1个master thread,1个行锁(lock)监控线程,1个错误监控线程。I/O thread的数量由配置文件中的innodb_file_io_threads参数控制,默认为4。(我的电脑ubuntu14.04安装的mysql默认8个I/O线程)。

2.2.2内存

InnoDB存储引擎内存由以下几个部分组成:缓冲池(buffer pool)、重做日志缓冲池(redo log buffer)以及额外的内存池(additional memory pool)。

缓冲池是占最大块内存的部分,用来存放各种数据的缓存。因为InnoDB存储引擎的工作方式总是将数据库文件按页(每页16K,不是4K)读取到缓冲池,然后按最近最少使用(LRU)的算法来保留在缓冲池中的缓存数据。如果数据库文件需要修改,总是首先修改在缓冲池中的页(发生修改后,该页即为脏页),然后再按照一定的频率将缓冲池的脏页刷新到文件。

缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲(insert buffer)、自适应哈希索引(adaptive hash index)、InnoDB存储的锁信息(lock info)、数据字典信息(data dictionary)等。

2.3master thread

即使某个事物没有提交,InnoDB存储引擎仍然会每秒将重做日志缓冲中的内容刷新到重做日志文件。所以再大的事物commit的时间也是很快的。

InnoDB的master thread会每隔一段时间将缓冲池的脏页刷新到磁盘中。

2.4关键特性

InnoDB的关键特性:插入缓冲、两次写、自适应哈希索引。

插入缓冲

InnoDB存储引擎开创性的设计了插入缓冲,对于非聚集索引的插入或更新操作,不是每一次直接插入索引页中。而是先判断插入的非聚集索引页是否在缓冲池中。如果在,直接插入;如果不在,则先放入一个插入缓冲区中,然后再以一定的频率执行插入缓冲和费聚集索引叶子节点的合并操作。这是通常能将多个插入合并到一个操作中(因为在一个索引页中),这就大大提高了对非聚集索引执行插入和修改操作的性能。

插入缓冲的使用需要满足以下两个条件:

  • 索引是辅助索引
  • 索引不是唯一的

两次写

插入缓冲带个InnoDB存储引擎的是性能,两次写带给InnoDB存储引擎的则是数据的可靠性。

当数据库宕机时,可能发生数据库正在写一个页面,而这个页只写了一部分(比如16k的页,只写前4k的页)的情况,我们称之为部分写失效。

doublewrite由两部分组成,一部分是内存中的doublewrite buffer,大小为2MB,部分是物理磁盘上共享表空间中连续的128个页,即两个区(extent),大小同样为2MB。当缓冲池中的脏页刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先拷贝到内存中的doublewrite buffer,之后通过doublwrite buffer再分两次,每次写入1MB到共享表空间之间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。在这个过程中,因为doublewrite页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成doublewrite页的写入后,再将doublewrite中的页写入各个表空间文件中,此时的写入则是离散的。

如果操作系统在将页写入磁盘的过程中崩溃了,在恢复过程中,InnoDB存储引擎可以从共享表空间中的doublewrite中找到该页的一个副本,将其拷贝到表空间文件,再应用重做日志。

自适应哈希索引

InnoDB存储引擎会自动根据访问的频率和模式来为某些页建立哈希索引。

拓展

  1. 系统故障造成数据库不一致的原因有两个:
    1.未完成事务对数据库的更新可能已写入数据库。
    2.已提交事务对数据库的更新可能还留在缓冲区没来得及写入数据库。
    在这里我们先说恢复的一般方法:
    (1)正向扫描日志文件(从头到尾),找出故障发生前已经提交的事务(存在begin transaction
    和commit记录),将其标识记入重做(redo)队列。同时找出故障发生时未完成的事务
    (只有begin transaction,没commit),将其标识记入(undo)队列
    (2)对undo队列的各事务进行撤销处理。进行undo的处理方法是,反向扫描日志文件,对每个undo
    事务的更新操作执行反操作,即将日志记录中“更新前的值”写入数据库。
    (3)对重做日志中的各事务进行重做操作。进行redo的处理方法是,正向扫描日志,对每个redo事务
    重新执行日志文件登记操作。即将日志中“更新后的值”写入数据库。
    以上三个步骤放于四海皆行。

参考

  • InnoDB中页的概念
  • InnoDB中的redo和undo
阅读全文
0 0
原创粉丝点击