InnoDB存储引擎2-InnoDB存储引擎

InnoDB存储引擎的版本

Mysql5.5 InnoDB1.1.X
Mysql5.6 InnoDB1.2X

InnoDb体系架构

后台线程

  • Master线程:缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲、undo页的回收。
  • IO线程:InnoDB存储引擎中大量使用AIO。IO线程主要工作是负责这些IO请求的回调
  • Purge线程:回收已经使用并分配的undo页。InnoDb1.1开始引入。
  • Page Cleaner Thread线程:脏页刷新操作。InnoDB1.2开始引入。

    内存

    缓冲池

    一共八种,分为Mysql缓冲和InnoDB缓冲
    ·

    LRU List、Free List和FlushList

    LRU:最近最久未使用,局部性原理。将页放到队首,查重。改进将选中页防止队列5/8处
    LFU:基于次数。
    优化点:
  • 设置midpoint;
  • 设置命中页到达热端的命中次数;
  • 设置热点页被刷出的概率;
  • show engine innodb status; innodb_buffer_pool_stats表。查看LUR、FreeList、命中率 等内存使用信息
    unzip_LRU:管理压缩后的页,页的默认大小为16KB
    伙伴算法:(申请4KB页为例)
  • 检查4DB的unzip_LRU列表,减产是否与可用的空闲页
  • 若有直接使用
  • 否则,检查8KBunzip_LRU列表
  • 若能够得到空闲页,将页分成2个4KB页,存放到4KB的unzip_LRU列表
  • 如不能得到空闲页,将LRU列表申请一个16KB的页,将页分为1个8KB的页和2个4KB的页
    Flush列表 保存脏页,同时脏页也保存在LRU列表中

    重做日志缓冲

    InnoDB存储引擎首先将重做日志信息放入到这个缓冲区,然后按一定频率将其刷新到重做日志文件。
    重做日志刷新到磁盘时机:
  • Master线程每一秒刷新一次
  • 每个事务提交时会刷新
  • 重做日志缓冲池空间小于1/2时

    额外内存池

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

    CheckPoint技术

    将脏页强制刷新到磁盘。解决问题:
  • 缩短数据库恢复时间
  • 缓冲池不够用时,将脏页刷新到磁盘
  • 重做日志不可用时,刷新脏页
    InnoDB通过LSN来标志版本,LSN是8字节的数字。每个页有LSN,重做日志中也有LSN,Checkpoint也有LSN。
    Sharp Checkpoint:
    默认工作方式,数据库关闭时将所有脏页刷新到磁盘
    Fuzzy Checkpoint:刷新时机
  • 间隔一段 时间刷新
  • 更新LRU列表刷新,被移除队列的页
  • 重做日志文件不可用,循环使用重做日志文件。P35???
  • 脏页太多 默认75页

Master 工作方式 P36

InnoDB 1.1

**磁盘操作会考虑IO的使用情况
每一秒的操作:

  • 日志缓冲刷新到磁盘,即使这个事务还没有提交 (总是)
  • 合并插入缓冲(可能)
  • 至多刷新100个脏页到磁盘
  • 没有用户活动切换到backgroud loop
    没十秒的操作:
  • 刷新100个脏页到磁盘
  • 合并至多5个插入缓冲(总是)
  • 删除无用的Undo页(总是)
  • 将日志缓冲刷新到磁盘(总是)
    刷新100个或者10 个脏页到磁盘(总是)
    backgroud loop 操作 没有用户活动或者关闭数据库
  • 删除无用undo页
  • 合并20个插入缓冲
  • 跳回到主循环

InnoDB关键特性

插入缓冲

背景:辅助索引插入的值不是单调递增或者单调递减。
操作:对于非聚集索引的插入或者更新操作,不是每一次直接插入到索引页,而是先判断插入的非聚集索引页是否在缓冲池中,若在,则直接插入;若不在,则先放入到一个InsertBuffer对象中,好似欺骗。然后再以一定的频率和情况进行Insert Buffer和辅助索引叶子节点的mege操作。
使用范围:辅助索引,索引不是唯一的

Chage Buffer

Insert、Delete、Update都进行缓冲,可以设置启用或禁止其中的某项。

Insert Buffer的内部实现 P51

InsertBuffer 数据结构是一颗B+树。全局一个B+树,这颗B+树放在表空间中,默认是ibdata1中。

space 表示 表空间id
offerset 表示页所在的偏移量
metadata 排序呢每个记录进入InsertBuffer的顺序
Insert Buffer BitMap 用来标记每个辅助索引页的可用空间。

两次写

重做日志中记录的是对页的物理操作,如偏移量800写‘aaaa’记录。如果这个页本身已经发生了损坏,在对其进行重做是没有意义的。这就是说,在应用重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是doublewrite。
doublewrite由两部分组成,一部分是内存中doublewrite buffer,大小为2MB,另一部分是物理磁盘上共享表空间中连续的128个页,即两个区,大小同样为2MB。在对缓冲池的脏页进行刷新时,通过memcpy函数将脏页先复制到内存doublewrite buffer,之后分两次,每次1MB顺序写入共享表空间的磁盘上,然后调用fsync函数,同步磁盘,避免缓冲写带来的问题。

自适应哈希索引

访问模式一样。以该模式访问100次,页通过该模式放了N次,页中记录/16.

异步IO

刷新临近页

启动、关闭和恢复

SQL

  • show engine innodb status; 查看innodb的状态信息
  • show variables like ‘%version%’;可以查看mysql和innodb的版本信息
  • innodb_file_io_thread 设置IO线程数量 innodb_read_io_thread;innodb_write_io_thread
  • innodb_purge_threads 设置purge线程数量
  • innodb_buffer_pool_size;缓冲池大小
  • innndb_buffer_pool_instances;InnoDB缓冲池数量;
  • 数据表innodb_buffer_pool_stats保存innoDB相关信息
  • innodb_old_blocks_time 页读取到mid位置后需要等待多久才会被加入到LRU的热端
  • innodb_buffer_page_lru表 查看LUR列表的信息
  • innodb_log_buffer_size 重做
  • innodb_lru_scan_depth LRU队列中可用页数量
  • innodb_lru_scan_depth LRU队列中空闲页的最小数值 默认1024
  • innodb_max_dirty_pages_pct 最大脏页数量,否则刷新会磁盘