2. InnoDB 体系结构
结构
InnoDB 引擎有多个内存块,组成一个大的内存池,负责如下工作:
- 维护所有线程需要访问的多个内部数据结构。
- 缓存磁盘数据,同时在对磁盘数据修改之前缓存。
- 重做日志(redo log)缓冲。
后台线程
主要作用:
- 刷新内存池数据;
- 将已修改数据刷盘;
- 异常恢复。
1. Master 线程
Master 线程是一个非常核心的后台线程,主要负责将缓冲池
中的数据异步
刷新到磁盘
,保证数据的一致性。
2. IO 线程
在InnoDB存储引擎中大量使用了AIO(Async IO)来处理写IO
请求,这样可以极大提高数据库的性能。
IO 线程的主要工作是:负责这些IO请求的回调(call back)处理
。
共有10个IO线程,分别是read(4)、write(4)、insert buffer、log IO 线程。使用innodb_read_io_threads
和innodb_write_io_threads
参数进行设置。
# 查看 InnoDB 版本;
SHOW VARIABLES LIKE'innodb_version';
# 查看读写线程数
SHOW VARIABLES LIKE'innodb_%io_threads';
# 观察InnoDB中的IO线程:
SHOW ENGINE INNODB STATUS;
status 显示的内容截取
IO线程0是插入缓冲,1是日志,然后是读写,并且读线程ID总是小于写线程。
3. Purge 线程
回收已经使用并分配的undo页。从master线程分离出来。
4. Page Cleaner 线程
刷新脏页。从master线程分离出来。
内存
内存结构
内存结构 内存1. 缓冲池
1.1 目的
由于CPU速度与磁盘速度之间的鸿沟,基于磁盘存储
的数据库系统通常使用缓冲池
技术来提高性能。所以,缓冲池的大小直接影响数据库的性能。
1.2 结构
缓冲池结构1.3 工作方式
读操作:
- 从磁盘读页存入缓冲池;
- 下次再读相同的页,先去缓冲池找,找不到再去磁盘找。
写操作:
- 首先修改缓冲池里的页;
- 以一定的频率刷盘(不是每次写都触发刷盘,而是 Checkpoint 机制);
- 可以设置
多个
来降低并发资源竞争,和ConcurrentHashMap
中的增加计数使用的分治思想
一样。
1.4 缓冲池管理策略
通常使用LRU(Latest Recent Used,最近最少使用)算法管理。即最频繁使用的页在LRU列表
的前端
,最少使用的页在尾端
。当缓冲池不够用的时候,释放尾端的页。
注意:
自适应索引、Lock信息、Insert Buffer等不需要LRU算法维护。
具体管理策略
LRU 列表
缓冲池每页默认大小16KB。InnoDB对传统LRU列表
加入midpoint
位置。新读取的页,不直接放到链表头部,而是放入5/8处。
LRU表分为3个:16KB表,8KB表,4KB表。分类管理,以便用来支持压缩页功能。3者之间使用伙伴算法
分配内存。
- 检查4KB的unzip_LRU列表,检查是否有可用的空闲页;
- 若有,则直接使用;
- 否则,检查8KB的unzip_LRU列表;
- 若能够得到空闲页,将页分成2个4KB页,存放到4KB的unzip_LRU列表;
- 若不能得到空闲页,从LRU列表中申请一个16KB的页,将页分为1个8KB的页、2个4KB的页,分别存放到对应的unzip_LRU列表中。
Free 列表
数据库刚启动时,LRU列表是空的,所有的页都在Free列表。
Flush 表
LRU表中的页被修改后,就是脏页(dirty page),即缓冲池中的页和磁盘中的页数据不一致。
注意:脏页既存在于LRU表,也存在于Flush表。LRU表用来提高读性能,Flush表用来将写数据刷盘,功能不一样。
重做日志缓冲
1. 工作方式
- 先将重做日志(redo log)放入这个Buffer;
- 按照一定频率刷盘。
2. 刷盘策略
- Master 线程每秒刷一次;
- 每个事务提交时触发刷盘;
- 剩余空间小于1/2时刷盘;
3. 大小
一般无需设置很大,因为每秒会刷盘,只要能保证每秒产生的事务量不超过 redo log Buffer 大小即可。
额外的内存池
InnoDB使用内存堆(heap)
的方式管理内存。一部分存放数据结构本身,一部分存放管理这些数据结构的管理信息,额外内存池就是存放管理信息。比如管理缓冲控制块(buffer control block),记录了LRU、锁、等待等信息,有点类似进程控制块(process control block)。
增大缓冲池也需要增大额外内存池。