InnoDB-----第2章 InnoDB存储引擎

第2章 InnoDB存储引擎


​ InnoDB是事务安全的MySQL存储引擎,设计上采用了类似与Oracle数据库的架构.通常来说,InnoDB存储引擎是OLTP应用中核心表的首选存储引擎.

1. InnoDB存储引擎概述

​ 该存储引擎是第一个完整支持ACID事务的MySQL存储引擎,其特点是行锁设计,支持MVCC,支持外键,提供一致性非读定锁,同事被设计用来最有效地利用以及使用内存和CPU.

2. InnoDB存储引擎的版本

  1. 老版本InnoDB:支持ACID,行锁,MVCC
  2. InnoDB 1.0.x:增加了compress和dynamic页格式
  3. InnoDB 1.1.x:增加了Linux AIO,多回滚段
  4. InnoDB 1.2.x:增加了全文索引支持,在线索引添加

3. InnoDB体系架构

​ InnoDB存储引擎内部有多个内存块,可疑人物这些内存块组成了一个大的内存池

img

​ 后台线程:主要作用是刷新内存池中的数据,保证缓冲池中的内存缓存是最近的数据,此外将已修改的数据刷新到磁盘文件,同时保证数据库发生异常的情况下InnoDB能恢复带正常的运行状态.

(1). 后台线程

​ InnoDB存储引擎是多线程的模型,因此其后台有多个不同的后台线程,负责处理不同的任务.

1). Master Thread

​ 主要讲缓冲池中的数据异步刷新到磁盘,保证数据的一致性.

2). IO Thread

​ InnoDB存储引擎中大量使用了AIO来处理写IO请求,这样可以极大提高数据库的性能,而IO Thread的工作只要是负责这些IO请求的回调处理.

3). Purge Thread

​ 回收已经使用并分配的undo页.

​ (undo:在操作数据前,现将数据备份到一个地方然后修改,这个备份叫undo log)

4). Page Cleaner Thread

​ 葬夜的刷新操作都放入到单独的线程来完成的.

(2). 内存

1). 缓冲池

​ InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理.因此可将其视为基于磁盘的数据库系统.

​ 缓冲池简单来说就是一块内存区域,通过内存的速度来弥补磁盘速度较慢对数据库性能的影响.在数据库中进行读取页的操作,首先将从磁盘中读到的页放在缓冲池中.在下一次在读取相同页时,首先判断该页是否在缓冲池中,如果在,称该页在缓冲池中被命中,直接读取该页,否则,读取磁盘上的页.

​ 对数据库中页的修改操作,则首先修改在缓冲池中的页,然后再以一定的频率刷新到磁盘上.

​ 缓冲池的大小直接影响着数据库的整体性能.

具体来看,缓冲池中缓存的页类型有:索引页,数据页,undo页,插入缓冲,自适应哈希索引,InnoDB存储的锁信息,数据字典等.

​ 从InnoDB 1.0.x版本开始,允许有多个缓冲池实例.每个页根据哈希值平均分配到不同的缓冲池实例中.

2). LRU list,Free list和Flush list

​ 通常来讲,数据库中的缓冲池是通过LRU(Latest Recent Used,最近最少使用)算法来进行管理的.及最频繁使用的页在LRU列表的前端,最少使用的页在LRU列表的尾端.当缓冲池不能存放新的页时,释放尾端的页.

​ 缓冲池中页的默认大小为16K.

​ InnoDB存储引擎还对传统的LRU算法进行了优化,加入了midpoint位置.

​ 新读取的页,虽然是最新访问的页,但是并不一定是经常活跃的页,直接放入列表前端有些不妥.InnoDB存储引擎的优化为将新页插入到设定好的midpoint位置.默认为列表长度的前5/8处.InnoDB存储引擎将midpoint前的表成为new列表,之后的页称之为old列表.(还有一个原因是,如果进行的是扫描操作,那么所有的页都会进入LRU列表一次,插入前端会刷新整个LRU列表)

​ InnoDB存储引擎还提供了innodb_old_blocks_time参数,用于设定读取页后多久将该页放入LRU列表的热端.

​ 刚启动数据库时,LRU列表是空的,所有的页都存放在Free列表中.当需要从缓冲池分配页时,首先从Free列表中查找是否有可用的空闲页,如果有将该空闲页从Free列表中删除,并插入到LRU列表中.否则从LRU列表尾端淘汰一个页,重新分配内存.

​ LRU列表中的页被修改后,被称为脏页.而Flush列表中的页即为脏页.需要注意的是,脏页既存在于Flush列表中,页存在于LRU列表中.

​ LRU列表用于管理缓冲池中页的可用性,Flush列表用来管理将页刷新会磁盘,二者互不影响.

3). 重做日志缓冲

​ InnoDB存储引擎首先将重做日志先放入到这个缓冲区,然后按一定频率将其刷新到重做日志文件,这个缓冲一般不会设置的很大,因为一般情况下每一秒都会有刷新操作.默认大小为8MB.

4). 额外的缓冲池

​ 在InnoDB存储引擎中,堆内存的管理是通过一种成为内存堆的方式进行的,在对一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请,当该区域的内存不够时,会从缓冲池中进行申请.

4. Checkpoint技术

​ 为了避免发生数据丢失的问题,当前的事务数据库系统普遍都采用了Write Ahead Log策略,即当事务提交时,先重写日志,再修改页.

​ 那么试想,是不是可以只保存日志,完全通过日志来恢复整个数据库系统中的数据带宕机发生的时刻,这需要两个前提条件:

  1. 缓冲池可以缓存数据库中所有数据
  2. 重做日志可以无线增大

​ 如果上面两个条件都满足,还需要考虑宕机后数据恢复的时间.

​ 所以,出现了Checkpoint技术,当数据库发生宕机时,不需要重做所有的日志,因为Checkpoint之前的页都已经刷新回磁盘了.当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,如果此页为脏页,会强制执行Checkpoint,将脏页刷新回磁盘.

​ 对于InnoDB存储引擎而言,是通过LSN来标记版本的.而LSN是8字节的数据,其单位是字节.

在InnoDB存储引擎内部,有两种Checkpoint:

  • Sharp Checkpoint:刷新全部脏页
  • Fuzzy Checkpoint:在InnoDB内部使用,只刷新部分脏页

发生Fuzzy Checkpoint的几种情况:

  1. Master Thread Checkpoint:在Master Thread中定时发生的.
  2. FLUSH_LRU_LIST Checkpoint:为了保证LRU列表中有差不多100个空闲页,当移除尾端页时,会进行Checkpoint.
  3. Async/Sync Flush Checkpoint:重做日志不可用时,会将一些页强制刷新回磁盘.
  4. Dirty Page too much Checkpoint:脏页数量太多,会发生Checkpoint

5. Master Thread的工作方式

(1). InnoDB 1.0.x版本之前

​ 内部由多个循环组成:主循环(loop),后台循环(backgroup loop),刷新循环(flush loop),暂停循环(suspend loop).Master Thread会根据数据库的状态在这些循环之间进行切换.

​ Loop被称为主循环,其中有两大操作-----每十秒的操作和每秒都进行的.

​ loop循环通过thread sleep实现,这意味这这些操作之间的计时是不准确的.

每一秒进行的操作:

  • 日志缓冲刷新到磁盘,即时还没有提交事务
  • 可能会合并插入缓冲(通过判断前一秒发生IO的次数判断IO压力是否小,从而决定是否进行合并插入缓冲)
  • 可能会刷新脏页到磁盘(脏页比例超过参数设置的值,会进行刷新,默认值为90%)
  • 如果当前没有用户活动,可能会切换到backgroup loop

每十秒进行的操作:

  • 可能会刷新100个脏页(判断过去十秒内IO次数是否小于200次)
  • 合并最多5个插入缓冲
  • 将日志缓冲刷新到磁盘
  • 删除无用的undo页
  • 刷新100或者10个脏页到磁盘

​ 如果当前没有用户活动或者数据库关闭,就会切换到background loop,在这个循环内,会执行以下操作:

  • 删除无用的Undo页
  • 合并20个插入循环
  • 跳回到主循环
  • 也可能会调到flush loop中不断刷新100个页直到符合条件

(2). InnoDB 1.2.x版本之前

​ 在之前的版本中,由于硬编码,即时每秒内有很多的页写入和多个插入缓冲的合并,Master Thread只会选择刷新其中的100个脏页和20个插入缓冲,当发生宕机时,会积累很多的数据没有刷新回磁盘,导致恢复的时间会需要很久.

​ 从InnoDB 1.0.x版本开始,提供了innodb_io_capacity参数来表示磁盘IO吞吐量,默认为200.对于刷新到磁盘的数量,会按照该参数的百分比进行控制:

  • 合并插入缓冲时,每次合并数量为该参数的5%.
  • 刷新脏页时,刷新的数量为该参数的值.

​ 从InnoDB 1.0.x版本开始,刷新脏页时的脏页占比参数innodb_max_dirty_pages_pct默认值由90变为了75.加快了脏页的刷新频率.

​ 引入了参数来判断需要刷新脏页的最适合的数量,其内部方法通过判断重做日志的速度来判断最适合的刷新脏页数量.

​ 引入了控制每次full purge()回收Undo页的数量的参数,默认为20.

​ InnoDB还对主循环内部进行了优化,使压力大时不一定总是等待1秒.

(3). InnoDB1.2.x版本

​ 对于脏页的刷新操作,从Master Thread线程分离到一个单独的Page Cleaner Thread进行.

6. InnoDB关键特性

(1). 插入缓冲

1). Insert Buffer

​ Insert Buffer和数据也一样,也是物理页的一部分,并不是缓冲池的组成.

​ 在InnoDB存储引擎中,主键是行唯一的标识符,通常应用程序中行记录的插入都是按照主键递增的顺序插入的.

​ 但是对于非聚集索引,插入的顺序是离散的.(聚集索引是指数据航的物理顺序与列值的逻辑顺序顺序相同,一张表中只能有一个索引)

​ InnoDB存储引擎开创性的设计了Insert Buffer,对于非聚集碎银的插入或更新操作,不是每一次的直接插入到索引页中,而是先判断插入的非聚集索引是否在缓冲池中,如果在直接插入(这样是直接操作内存的,很快),如果不在,先放入一个Insert Buffer对象中.然后在以一定的频率将多个插入合并到一个操作中.

Insert Buffer的使用必须满足一下两个条件:

  1. 索引是辅助索引:叶子节点中存储主键值,每次查找时,现根据索引找到叶子节点中的主键值,才从聚集索引中得到完整记录.
  2. 索引不是唯一的:如果唯一,每一次插入会先查找判重复,违背了Insert Buffer减少操作索引次数的目的.

​ 但是,Insert Buffer存在一个问题,在写密集的情况下,插入缓冲会占用过多的缓冲池内存(虽然保存在物理磁盘,但是缓冲池中还是有这部分信息的)

2). Change Buffer

​ 从InnoDB 1.0.x版本开始引入了Change Buffer,可将其视为Insert Buffer的升级.从这个版本开始,可以对DML操作-----insert,delete,update都进行缓冲.

3). Insert Buffer的内部实现

​ Insert Buffer的数据结构是一颗B+树,非叶节点存放的是查询的search key(键值).

search key占9字节:

  • space:4字节,表示待插入记录所在表的表空间id.
  • marker:1字节,用来兼容老版本的Insert Buffer.
  • offset:4字节,表示页所在的偏移量.

叶节点存储的数据结构如下:

  • 前三个字段和search key一样,共占9字节.
  • metadata:4字节,又分为以下三个部分:
    • IBUF_REC_OFFSET_COUNT:2字节,表示进入Insert Buffer的顺序.
    • IBUF_REC_OFFSET_TYPE:1字节
    • IBUF_REC_OFFSET_FLAGS:1字节
  • secondary index record:实际插入的值.

​ 为了保证每次合并插入缓冲都必须成功,必须要有一个特殊的页来标记每个辅助索引页的可用空间,类型为Insert Buffer Bitmap.

​ 每个Insert Buffer Bitmap页用来追踪16384个辅助索引页,也就是256个区.每一个Insert Buffer Bitmap都会紧跟在这16384个页后面.

4). Merge Insert Buffer

Merge Insert Buffer(合并)操作发生在以下几种情况下:

  • 辅助索引被读取到缓冲池
  • Insert Buffer Bitmap页追踪到该辅助索引页没有可用空间(剩余空间不足1/32页)
  • Master Thread(主循环定时合并),每次只合并一部分页,由InnoDB存储引擎在Insert Buffer B+树中随机读取

(2). doublewrite

​ 也就是两次写.

​ 如果在InnoDB存储引擎写入一个页的过程中,发生了宕机,此时这个页被写了一半,已经与前一次Checkpoint后的磁盘不一致了,使用重做日志是无法恢复的.

​ doublewrite由两部分组成,一部分是内存中的doublewrite buffer,大小为2MB,另一部分是物理磁盘上共享表空间中的123个页(两个区),大小也为2MB.

​ 在对脏页进行刷新时,会先将脏页先复制到内存中的doublewrite buffer,然后同步磁盘,这个操作非常快.完成之后在将doublewrite buffer中的页写入到各个表空间中.相当于在本地磁盘中先快速写入一遍,作为副本,这个副本和本地磁盘中的数据总有一个是干净的.

(3). 自适应哈希索引

​ InnoDB存储引擎会监控对表上个索引的查询.如果观察到建立哈希索引可以带来速度提升,则建立哈希索引(Adaptive Hash Index,AHI).AHI是通过缓冲池的B+树构造而来,因此建立的速度很快,而且不需要对整张表构建哈希索引. InnoDB存储引擎会自动根据访问的频率和博士来自动地为某些热点页建立哈希索引.

​ 有一个要求就是对这个页的连续访问必须使用相同的查询条件.

​ 哈希索引只能用来搜索等值的查询.对于范围查找,是不能使用哈希索引的.

(4). 异步IO

​ 为了提高磁盘操作性能,当前的数据库系统都采用异步IO(AIO)的方式来处理磁盘操作.与之相对应的是Sync IO,即没进行一次IO操作,需要等待此次操作结束才嫩而过继续接下来的操作.

​ 异步IO就是指用户可以在发出一个IO请求后立即在发出另一个IO请求,全部的IO请求发出后,等待所有的IO操作完成,这就是AIO.

​ 另一个优势,是可以进行IO Merge操作,也就是将多个IO合并为一个IO请求,从而提高IOPS性能.

(5). 刷新邻接页

​ 当刷新一个脏页时,InnoDB存储引擎会尖刺该页所在的区的所有页,如果是脏页,那么一起进行刷新.

​ 对于固态硬盘,建议关闭此特性.

7. 启动,关闭与修复

​ 关闭数据库时,参数innodb_fast_shutdown影响着存储引擎为InnoDB的表的行为.

innodb_fast_shutdown参数含义:

  • 0:MySQL关闭时,InnoDB需要完成所有的无用Undo页清除和合并插入缓存,并且刷新所有脏页会磁盘.
  • 1:只刷新脏页.
  • 2:将日志写入日志文件,下次MySQL数据库启动时进行恢复.

​ 参数innodb_force_recovery影响了整个InnoDB存储引擎恢复的状况.该参数默认为0,表示当需要恢复时,进行所有的恢复操作,当不能进行有效恢复(比如发生了数据库坏块),MySQL数据库可能发生宕机,并将错误记录到错误日志中.还有6个可以设置的值来屏蔽一些错误.

​ 当innodb_force_recovery参数不为0时,insert,update和delete这类DML操作都是不允许的.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值