innodb架构以及三大特性
innodb总体架构
分为内存结构、磁盘结构
Innodb存储引擎 逻辑存储单元
表、段、区、页、行
内存结构——buffer pool
由于内存和磁盘有巨大的I/O鸿沟,因此引入了缓冲区—buffer pool,从而提高数据库的并发处理能力;
数据页(page)是InnoDB磁盘I/O的最小单位
缓冲区中page默认 16k 操作系统的page默认 4k
buffer pool 主要分为三个部分buffer pool、change buffer 、Adaptive Hash Index,另外还有redo log buffer;
buffer pool
缓存innodb表的数据,包括数据页、索引页、插入缓冲、数据字典等;默认128M 可调整
如果缓冲池满了怎么办?LRU 算法(改良后,与传统LRU不同 分为old和young数据)
change buffer
使用条件:
-
索引是二级索引
-
索引不是唯一索引
change buffer 可以缓存DML操作(insert、update、delete)的修改,从而提升语句的执行速度;
为什么呢?
因为二级索引的数据插入是相对随机的,所以先把修改的数据缓存到change buffer ,然后change buffer再同步到数据页,提升效率;
change buffer 数据同步到数据页的操作成为merge,可以避免从磁盘将辅助索引页读入缓冲池所需的大量随机访问I/O;
adaptive hash index
redo log buffer
事务在内存中的缓存
Buffer状态及链表结构
数据存放在page中,就是对应内存中的buffer,每个buffer分三个状态
-
free buffer :buffer未被使用
-
clean buffer:内存中buffer的数据与磁盘保持一致
-
dirty buffer:内存中新写入的数据还没有刷新到磁盘,与磁盘数据不一致
buffer在内存中需要被组织起来,由链来管理。innodb是双向链表的结构,三种不同buffer状态衍生出来三条链
- free list:把free状态的buffer链起来,每次有page调入到内存,优先判断free buffer的使用情况,如果不够,就会从lru list 和flush list释放出buffer,来多的新的free buffer;
- lru list:会把最近最少使用的clean状态的buffer串联起来,释放出新的free buffer
- flush list:把dirty状态的buffer串联起来,方便刷盘。推进checkpoint lsn,使实例崩溃后,可以快速恢复;
各个刷新线程以及作用
redo log thread: 负责把redo log buffer中的数据刷新到redo log文件
change buffer thread: 把change buffer中的数据刷新到磁盘
read/write thread: 数据库的读写请求线程
page clean thread:负责脏页刷新的线程
purge thread: 负责删除undo页;由于进行DML语句都会生成undo日志,因此需要定期清理undo,这时就需要purge操作
checkpoint thread: 在redo log 发生切换时,执行checkpoint。redo log发生切换或者redo log写满,就会触发把脏页刷新到磁盘。而且还会把redo log 刷新到磁盘,实现数据的持久化,避免数据丢失。
内存刷新机制
redo log
基于磁盘的物理日志,redo log属于innodb磁盘结构中的部分。
redo log 默认 两个 ib_logfile0,ib_logfile1,顺序写,循环写。通过LSN记录位置。
但是redo log的生成也并不是每次都记录到磁盘,通过参数innodb_flush_log_at_tx_commit来控制
-
0(延迟写):redo log thread每隔一秒会将缓冲区中的日志刷新到redo log,同时将数据flush到磁盘的数据文件;每次事务提交,并不会触发redo log thread的将缓冲区数据刷新到redo log;
-
1(默认,实时写,实时刷):每次事务提交,触发redo log thread 将缓冲区中的日志刷新到redo log中,同事将数据刷盘到数据文件;
-
2(实时写,延时刷):每次事务提交,redo log thread将缓冲区中的日志刷新到redo log;但是并不会触发flush。而是每秒会将数据flush刷新到磁盘的数据文件;
三种状态的对比:
延迟写:性能最高但是不太安全,一旦数据库崩溃会丢失一秒的数据;
实时写,实时刷:安全性最高,性能最低
实时写,延时刷:介于前两者之间
undo log
属于逻辑日志,undo log是与单个读写事务相关联的撤消日志记录的集合。undo log记录包含关于如何撤消事务对聚集索引记录的最新更改的信息。如果另一个事务需要查看作为一致读操作一部分的原始数据,则从撤销日志记录中检索未修改的数据。
undo log的位置:撤消日志存在于撤消日志段中,撤消日志段包含在回滚段中。回滚段位于系统表空间、undo表空间和临时表空间中。
为什么undo log不需要持久化,只是逻辑日志?
驻留在临时表空间中的Undo日志用于修改用户定义临时表中的数据的事务。这些撤消日志不需要重做日志,因为崩溃恢复不需要它们。它们仅用于服务器运行时的回滚。这种类型的撤销日志可以避免重做日志I/O,从而提高性能。
Innodb三大特性
change buffer(提升性能)
影响数据库的主要性能就是磁盘I/O,而change buffer就是把二级索引的DML操作从随机I/O变成顺序I/O,从而提升I/O的效率。
insert buffer
先介绍一下insert buffer,在对非聚集索引的插入和更新操作,不是每一次都插入到索引页中,而是先判断插入的索引页是否在缓冲区,若存在,则直接插入;如果不在就先插入到一个insert buffer中;然后再以一定的频率将insert buffer辅助索引页子节点进行merge操作,这是通常能将多个插入合并到一个操作中(因为在一个索引页中),从而提高对于非聚集索引的插入效率;
change buffer 是insert buffer 的升级,可以对DML操作-insert、update和delete都进行缓冲。
可以设置对缓冲的DML操作进行设置,通过innodb_change_buffering设置,默认all
innodb_change_buffer_max_size 设置change buffer占用缓冲区的比例,默认25%,建议调成50%
double write(提升可靠性)
问题:
因为刷脏不是实时进行的,比如说脏数据页有16k,刷脏只同步了4k的时候服务器宕机了,此时该数据页被破坏,怎么能避免数据丢失(写失效)呢?
double write buffer 的组成部分:内存中的double write buffer ,2M;磁盘共享表空间中的连续的128个也,两个区,同样也是2M
数据页刷出的脏数据,在同步到磁盘之前会先将脏页中的数据复制到double write buffer中,然后double write buffer 分两次,每次1M将数据顺序的写入到共享表空间的物理磁盘上,然后double write buffer马上调用函数,同步磁盘;在这个过程中因为因为double write 页是连续的,顺序写,所以开销并不是很大。
首先根据磁盘中的double write(副本)修复page页,然后在通过redo log 进行数据崩溃恢复。