文章目录
1 MySQL体系结构
- 数据库:文件的集合,是依照某种数据模型存放于存储器中的数据集合
- 数据库实例:程序,是位于用户和操作系统之间的数据管理软件,用户对数据库数据的任何操作都是通过实例进行的
MySQL体系结构
2 InnoDB存储引擎概述
存储引擎是基于表的,而不是数据库
- InnoDB存储引擎支持事务,主要面向在线事务处理(OLTP)的应用
- 特点是行锁设计、支持外键、支持非锁定读
- 使用多版本并发控制(MVCC)来获得高并发性
- 实现了SQL的4种隔离级别
- 使用next-key locking的策略来避免幻读产生
- 从MySQL4.1开始将每个InnoDB存储引擎的表单独存放到一个独立的ibd文件中
3 InnoDB体系架构
- 后台线程:主要负责刷新内存池中的数据
- 内存:维护线程访问的数据结构、缓存磁盘上的数据等
3.1 后台线程
InnoDB存储引擎是多线程的模型
- Master Thread:核心后台线程,负责将缓冲池中的数据异步刷新到磁盘,保证数据一致性
- IO Thread:InnoDB使用AIO(Async IO)来处理写IO请求,IO Thread负责这些IO请求的回调,有10个线程,分别是4个write thread、4个read thread、insert buffer thread、log thread
- Purge Thread:事务提交后,undolog不再需要,使用Purge Thread来回收
- Page Cleaner Thread:负责脏页的刷新操作
3.2 内存
-
缓冲池:InnoDB存储引擎是基于磁盘存储的,按照页的方式进行管理。缓冲池就是通过内存的速度来弥补磁盘的速度。缓冲池页的大小默认为16KB,页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发,而是通过checkpoint的机制刷新回磁盘
- LRU列表:缓冲池通过最近最少使用LRU算法进行管理,但在InnoDB存储引擎中,LRU列表来加入了midpoint位置,新访问的页并不是加在LRU列表首部,而是放在midpoint位置。InnoDB中,把midpoint之后的列表称为old列表,midpoint之前的列表称为new列表(最活跃的热点数据),并维护一个参数,用于表示mid位置后需要等待多久才能被加入到LRU列表的热端。页从old到new称为page made young,没有从old到new称为page not made young
- Free列表:当数据库刚启动时,LRU列表是空的,页都放在Free列表中。当需要从缓冲池中分页时,首先从Free列表中查找是否有可用的空闲页,如果有则从Free列表删除,放入LRU列表中;否则根据LRU算法进行淘汰
- Flush列表:在LRU列表中的页被修改后,称为脏页,即缓冲池的页和磁盘上的页不一致。由Flush列表存储,通过checkpoint机制将脏页刷新回磁盘
- 压缩页:对于非16KB的页,通过unzip_LRU列表管理。例如申请4KB的页,首先检查是否有4KB的空闲页,若没有则检查8KB,将其分成2个4KB,若没有则从LRU列表申请一个16KB的页,将其分成1个8KB和2个4KB
-
重做日志缓冲:InnoDB首先将重做日志信息放入到缓冲区,然后按一定频率(一般情况,每一秒钟)将其刷新到重做日志文件
-
额外内存池:在InnoDB中,内存的管理通过内存堆进行。对一些数据结构本身的内存进行分配时,需要从额外的内存池中进行申请,当该区域的内存不够时,会从缓冲池进行申请
4 Checkpoint
Write Ahead Log策略:当事务提交时,先写重做日志,再修改页。即使由于宕机而导致数据丢失,也能通过重做日志完成数据恢复
检查点技术目的是解决以下问题
- 缩短数据库恢复时间:检查点之前的页已经刷新回磁盘,不需要再恢复
- 缓冲池不够用时,将脏页刷新到磁盘:根据LRU算法淘汰的页如果时脏页,则强制执行checkpoint,将脏页刷回
- 重做日志不可用时,将脏页刷新到磁盘:重做日志中不需要恢复的部分可以被重用,如果此时重做日志还需要使用,则强制执行checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置
InnoDB中的两种checkpoint
- Sharp Checkpoint:发生在数据库关闭时将所有脏页刷新回磁盘
- Fuzzy Checkpoint:每次只刷新一部分脏页
5 Master Thread
Master Thread具有最高的线程优先级别,内部由多个循环组成,Master Thread根据数据库状态在不同循环中切换
- 主循环(loop):大多数操作在这个循环中,分为每秒的操作和每10秒的操作
- 每秒的操作包括
- 日志缓冲刷新到磁盘,即使这个事务还没有提交(总是)
- 合并插入缓冲(可能)
- 最多刷新100个脏页到磁盘(可能)
- 如果当前没有用户活动,切换到background loop(可能)
- 每10秒的操作包括
- 日志缓冲刷新到磁盘(总是)
- 合并最多5个插入缓冲(总是)
- 刷新100个脏页到磁盘(可能的情况下)
- 刷新100个或者10个脏页到磁盘(总是)
- 删除无用的undo页(总是)
- 每秒的操作包括
- 后台循环(background loop):如果当前没有用户活动或者数据库关闭时,就会切换到这个循环
- 删除无用的undo页(总是)
- 合并20个插入缓冲(总是)
- 跳回主循环(总是)
- 不断刷新100个页知道符合条件(可能,跳转到flush loop)
- 刷新循环(flush loop):如果没有事情做,则跳转到suspend loop
- 暂停循环(suspend loop):将Master Thread挂起
InnoDB1.0.x版本之后,维护一个参数表示磁盘IO吞吐量,默认为200,合并插入缓冲时,数量为这个参数的5%,刷新脏页时,数量为这个参数
6 InnoDB关键特性
6.1 插入缓冲
使用原因:一个表上有多个非聚集的辅助索引且不是唯一,对于这类的非聚集索引页的叶子节点插入不是顺序的,离散的访问非聚集索引页导致插入操作性能下降
Insert Buffer:对于非聚集索引的插入或更新操作,不是每一次直接插入索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,若在则直接插入;若不再则先放到Insert Buffer对象中,再以一定的频率进行Insert Buffer和辅助索引页子节点的merge操作,通常能将多个插入合并到一个操作中,提高插入性能
Insert Buffer要同时满足:索引是辅助索引,索引不是唯一的
Insert Buffer数据结构:B+树
Change Buffer:可视为Insert Buffer的升级,对一条记录的UPDATE操作分为将记录标记为删除和真正将记录删除
6.2 两次写
由两部分组成,一部分是内存中的doublewrite buffer,大小为2MB,另一部分是磁盘上的128个页,大小为2MB
在对缓冲池的脏页进行刷新时,不直接写磁盘,而是通过memcpy将脏页先复制到内存的doublewrite buffer中,再通过doublewrite buffer分两次,每次1MB顺序的写入磁盘上的doublewrite,完成之后,再将这里面的页写入各个表空间文件中
6.3 自适应哈希索引
InnoDB会监控对表上各索引页的查询,如果建立哈希索引可以提升性能,则建立哈希索引,称为自适应哈希索引AHI
AHI是通过缓冲池的B+树页构造而来,不需要对整张表构建哈希索引
6.4 异步IO
用户可以在发出一个IO请求后立即再发出另一个IO请求,当全部IO请求发送完毕后,等待所有IO操作完成
6.5 刷新邻接页
当刷新一个脏页时,InnoDB会检测该页所在区的所有页,如果是脏页,那么一起进行刷新
7 InnoDB关闭
在关闭时,参数innodb_fast_shutdown影响着InnoDB的行为
- 0:数据库关闭时,InnoDB需要完成所有的full purge和merge insert buffer,将所有脏页刷新回磁盘,这需要一些时间
- 1:默认值,不需要完成上述的full purge和merge insert buffer,但是缓冲池中的脏页还是会刷新回磁盘
- 2:都不完成,而是将日志写入日志文件,下次数据库启动时,进行恢复操作