InnoDB存储引擎
innoDB的各个版本对比
image.pnginnoDB的整体架构
image.png后台线程
- master thread
1.赋值将缓冲池中的数据异步刷到磁盘,保证数据的一致性。
- 刷新脏页,合并插入缓冲,UNDO页的回收等
- IO tread
1.innodb采用AIO来处理写IO,而IO thread就是处理这些IO请求的回调
2.Io thread有:write,read,insert bufeer和log
image.png3.可以通过innodb_read_io_threads和innodb_write_io_threads来设置read和write的线程数,insert bufeer和log固定为1个
- purge thread
1.undo log用于存放事务提交前原始的数据,如果事务已经提交了,则undo可以通过purge thread回收
2.可以设置多个purge thread 回收undo 页
- page cleaner thread
1.将脏页的刷新操作都放入到page cleaner thread
内存
- 缓冲池
1.innodb中的记录按照页的方式进行管理。
2.将磁盘读到的页放在缓冲池,这个过程称为将页FIX在缓冲区
3.对页修改是先修改缓冲池的页,然后再以一定的频率刷新到磁盘上
4.页从缓存池刷新会磁盘的操作并不是每次页发生变更的时候,而是通过checkpoint机制
5.通过innodb_buffer_pool_size来设置和这个缓冲池大小
image.png6.内存数据对象包含以下,其中缓冲池包含:数据页,插入缓冲,锁信息,索引页,自适应哈希索引,数据字典信息
7.可以有多个缓冲池实例,每个页根据hash值平均分配到不同的缓冲池实例,这样就减少数据库内部资源竞争
8.innodb_buffer_pool_instances来设置多少个缓冲值实例。
- LRU List,Free List 和Flush List
1.LRU List,Free List 和Flush List这三个是用来管理缓冲池内容的方式
2.LRU最近最少使用方式,前端存放使用最频繁,最少使用存放尾部。最新读到的页面,将首先存放在尾部。(innodb做了优化,把最新的页存放在midpoint位置,默认是在LRU列表长度的5/8)
3.在innodb中把midpoint之后的称为old,之前的称为new。即new是最活跃的热点数据
4.设置innodb_old_blocks_time,来标识页读取到mid位置后需要等待多久才会被加入到LRU列表的热端
5.数据库刚启动LRU是空的,页都存放在Free列表中,我们获取页,优先从free中获取
- LRU列表淘汰的末尾页,将该内存空间分配给新的页
7.当支持压缩页后,页变为 1KB,2KB,4KB和8KB,对于非16KB的页管理,通过unzip_LRU进行管理
8.我们正常得到的LRU页包含unzip_LRU
9.unzip_LRU分配页方法(比如想获取4KB),首先检查4KB的unzip_LRU列表是否有可用的空闲页,没有的话检查8KB的列表,如果有则将8KB分成2个4KB,放入到4KB列表,若还是得不到则从16KB申请一个页,拆分成1个8KB的页,2个4KB的页,分别存放对应的unzip_LRU
10.在LRU列表中被修改的页,我们称之为脏页,通过checkPoint机制将脏页刷新会磁盘,flush列表就是脏页列表
11.脏页即存在于LRU也存在Flush列表(因为还需要使用)
- redo log buffer
- innodb会将重做日志信息放入到这个缓冲区,然后以一定的频率将其刷新到重做日志文件(redo log file)
2.通过设置innodb_log_buffer_size设置这个redo log buffer
3.以下三种情况会将redo log buffer刷新到redo log file:master thread每秒钟会刷新,当事务提交时候,当重做buffer剩余空间大小小于一半
- 额外的内存池
checkpoint
- 1.为了避免在内存中脏页还未刷到磁盘,系统宕机导致数据都是,采用了write ahead log
- 2.write ahead log:即事务提交的时候,先写redo log file(即把redo log buffer 转化为文件)
- 3.如果redo log file 太大了会导致,数据库启动时候恢复需要很长时间,且成本太高
- 4.checkPoint:缩短数据库的恢复时间,缓冲池不够用时候将脏页刷新到磁盘,重做日志不可用的时候刷新脏页。
- 5.宕机之后,checkpont之前的页都已经刷新到磁盘,只需要对checkpoint后的重做日志进行恢复。
- 6.单缓冲池不够用,LRU会溢出最近最少使用的页溢出,若是脏页则会执行checkpoint,即将脏页刷新到磁盘
- 7.因为对重做日志都是循环使用的,当我们重做日志快用满了,这个时候如果还想使用重做日志,那么需要把内存中国对应的页给刷到磁盘,才可以覆盖那部分被刷到磁盘页对应的重做日志
- checkpoint的类型:sharpCheckPoint
,Fuzzy CheckPoint.
- 9.sharpCheckPoint:发生在数据库关闭时候,将所有的脏页刷新回磁盘,这是默认的工作方式,通过参数innodb_fast_shutdown=1
- 10.Fuzzy CheckPoint.:master thread checkPoint,FLUSH_LRU_LIST checkPoint,Async/Sync flush check point,Dirty Page too much check point
- master thread checkPoint:每个一段时间刷新一定比例,是异步操作。
- 12.FLUSH_LRU_LIST checkPoint:被移除LRU列表的脏页会被回收.通过page cleaner thread 去操作
- 13.Async/Sync flush check point:只重做日志不可用,这时候强制将一些页刷新回到磁盘,放入到page cleaner thread 中操作
- Dirty Page too much check point:强制刷新一部分脏页到磁盘
masterThread的工作方式
-
最初该线程内部又多个loop组成,loop,background loop,flush loop,suspend loop
-
loop 分为 每秒操作和每十秒操作,
-
loop 每秒操作:日志缓冲刷新到磁盘,即时事务还没提交(总是),合并插入缓冲(可能),至多刷新100个脏页到磁盘(可能),如果当前没有事务提交,则契合到backgroup loop
-
loop 每十秒操作:刷新100个脏页(可能),合并至多5个插入缓冲(总是),将日志缓冲刷新到磁盘(总是),删除无用的undo(总是),刷新100个或者10个脏页到磁盘
-
background loop:数据库空闲,或者关闭,就会切换到这个循环。
-
background loop:删除无用的undo(总是),合并20个插入缓冲(总是),调到主循环(总是),不断刷新100个页直到符合条件(可能,跳转到flush loop中完成)
-
如果flsuh loop 没有脏页要刷新,则会切换到suspend_loop,将master thread 挂起
-
之后的改革就是 合并插入缓冲时候,合并插入缓冲的数量是 innodb_io_capacity的5%,从缓冲区刷新脏页的数量就是innodb_io_capacity
-
剔除了innodb_adaptive_flushing ,用来判断每次刷新多少脏页
-
把 刷新脏页的操作转移给page cleaner thread
innodb关键特性
- 插入缓冲:其是物理页的一部分,不是缓冲区的一个部分,对于插入或者更新的时候,先判断对应的非聚集索引页是否在缓冲池,若是在直接插入,不在的话则先放入到一个insert buffer中,然后在以一定的频率和情况进行insert buffer和辅助索引的叶子结点的merge。需要索引不是唯一且是辅助索引。以后的change buffer 作用与insert buffer一样只是还可以作用于delete等
-
我们每次删除记录都是现将记录标识位已删除,然后再真正删除
-
两次写:如果数据写到页,写了一半发生宕机,那么这个页就是被损坏,如果通过redo log无法对其redo 因为redo log 是对页进行物理操作,,写入发生失效,我们先通过页的副本替换页,然后在进行重做。这就是double write
-
double write包含double write buffer 为2M,还有磁盘上128个连续页,大小同样为2M。在对缓冲池的脏页进行刷新时候,并不直接写盘,而是先将脏页数据复制到内存中double write buffer ,然后double write 分为2次 1m的去写,直接同步到磁盘。因为double write的页是连续的所以开销不大,然后我们在将double write buffer 写入各个表空间
-
我们在恢复空间只需要将double write 页中的数据直接复制到表空间文件,在应用重做日志
image.png -
redo 是物理和逻辑日志的结合,每次记录哪个页,发生了什么操作,当我们页被污染了,这个时候再去写,很有可能造成数据不一致。所以需要换一个新的页
-
为啥redo 不需要 doubble write
-
这个博客记录了 为啥我们同时需要double write和redo :https://www.cnblogs.com/geaozhang/p/7241744.html
-
自适应哈希索引:innodb观察到如果给表加上hash索引可以提高速度,即对热点查询建立自适应hash,
-
异步io:read ahead和脏页的刷新都是依靠AIO
-
刷新邻接页:刷新一个脏页,发现这个页所在去的所有页,如果是脏页,那么久一起进行刷新,这样的好处是通过AIO将多个IO写入合并为一个
-
对于不怎么脏的脏页 也刷新了,或者固态硬盘不需要。所以可以关闭