InnoDB体系结构学习笔记

后台线程

Master Thread

核心的后台线程,主要负责将缓冲池的数据异步刷新到磁盘,保证数据的一致性,包括(脏页的刷新)、合并插入缓冲、(UNDO页的回收)等

IO Thread

4个write、4个read、1个insert buffer、1个log

参数innodb_read_io_threads和innodb_write_io_threads可以进行设置。

Purge Thread

回收已经使用并分配的UNDO页。(从Innodb 1.1版本开始独立线程)

从Innodb 1.2版本开始,Innodb支持多个Purge Thread,进一步加快UNDO页的回收。同时由于Purge Thread需要离散的读取UNDO页,这样能更进一步利用磁盘的随机读取性能。

Page Cleaner Thread

在Innodb 1.2版本中引入,将之前版本中脏页的刷新操作都放入到单独的线程中完成。减轻Master Thread的工作以及用户查询线程的堵塞,进一步提高InnoDB存储引擎的性能。

内存

缓冲池

缓冲池的配置通过参数innodb_buffer_pool_size来设置。

show variables like 'innodb_buffer_pool_size';

缓冲池中缓存的数据页类型有:索引页、数据页、undo页、插入缓冲(insert buffer)、自适应哈希索引、Innodb存储的锁信息(lock info)、数据字典信息(data dictionary)等。

从InnoDB 1.0.x版本开始,允许有多个缓冲池示例。每个页根据哈希值平均分配到不同的缓冲池中。好处是减少数据库内部的资源竞争,增加数据库的并发处理能力。通过参数innodb_buffer_pool_instances来进行配置,默认为1。

show variables like 'innodb_buffer_pool_instances';

LRU List、Free List和Flush List

数据库中的缓冲池通常是通过LRU(Latest Recent Used,最近最少使用)算法进行管理的。即最频繁进行的页在LRU列表的前端,而最少使用的页在LRU列表的尾端。当缓冲池不能存放新读到的页时,将首先释放LRU列表中的尾端的页。

InnoDB的缓冲池对传统的LRU算法做了一些优化。在LRU列表中还加入了midpoint位置。新读取到的页,虽然是最新访问的页,但并不是直接放入到LRU列表的首部,而是放入LRU列表的midpoint位置。这个算法在InnoDB存储引擎下称为midpoint insertion strategy。默认情况下位置在LRU列表长度的5/8处。通过参数innodb_old_blocks_pct控制。

为什么不使用传统的LRU算法,如果直接将读取到的页放入到LRU的首部,那么某些SQL操作可能会是缓冲池中的页全部被刷出,从而影响缓冲池的效率。常见的这类操作为索引或数据的扫描操作。这类操作需要访问表中的许多页,甚至是全部的页,而这些页仅仅是这次操作需要的,并不是热点数据。

同时,InnoDB使用参数innodb_old_blocks_time管理页读取到midpoint位置后等待多久才会被加入到LRU的热端(midpoint之前的称为new列表热端,之后的列表称为old列表)。可以通过下面的设置尽可能使LRU列表中热点数据不被刷出。

set global innodb_old_blocks_time = 1000;

如果预估自己的热点数据不止63%,那么通过下面的设置来减少热点页的刷出,但是还是会被刷出。

set global innodb_old_blocks_time = 20;

当数据库刚启动时,LRU列表是空的,即没有任何的页。这是页都存放在Free列表中,当需要从缓冲池中分页时,首先从Free列表中查找是否可用的空闲页,若有则从Free列表中删除,放入到LRU列表中。否则,根据LRU算法,淘汰LRU列表末尾的页,分配给新的页。

当页从LRU列表的old部分加入到new部分时,称此时发生的操作为page made young,而因为innodb_old_blocks_time的设置而导致没有从old部分变为new部分的操作称为page not made young。

通过命令查看LRU列表及Free列表的使用状况。

show engine innodb statusG;
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137428992
Dictionary memory allocated 417853
Buffer pool size   8191
Free buffers       7724
Database pages     467
Old database pages 0
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 433, created 34, written 36
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 467, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]

在LRU列表中的页被修改后,称该页为脏页,即缓冲池中的页和磁盘上的页的数据产生了不一致。这是数据库会通过CHECKPOINT机制将脏页刷新回磁盘,而Flush列表中的页即为脏页列表。注意:脏页即存在于LRU列表中,也存在于Flush列表中。LRU列表管理缓冲池中页的可用性,Flush列表用来管理页刷新回磁盘,二者不影响。

重做日志缓冲

InnoDB存储引擎首先将重做日志信息放入重做日志缓冲区,然后按照一定的频率将其刷入到重做日志文件。由参数innodb_log_buffer_size控制,默认为8M。

重做日志在下面三种情况下会把重做日志缓冲中的内容刷新到外部磁盘的重做日志文件中。

  • Master Thread每一秒将重做日志缓冲刷新到重做日志文件。
  • 每个事物提交时会将重做日志缓冲刷新到重做日志文件。
  • 当重做日志缓冲池剩余空间小于1/2时,重做日志缓冲刷新到重做日志文件。

Checkpoint技术

如果使用Update或Delete操作,改变了页中的记录,那么此时页是脏的,即缓冲池中的页的版本比磁盘的新。数据库需要将新版本的数据从缓冲池刷新到磁盘。

但是不能每一次变化,都将新页的数据刷新到磁盘。一方面开销太大,再就是如果在刷新过程中发生了宕机,那么数据不能恢复,为了避免发生数据丢失的问题,数据库普遍采用Write Ahead Log策略,即当事务做日志提交时,先写重做日志,再修改页。如果发生宕机,通过重做日志文件来完成数据的恢复。

如果缓冲池缓存数据库中所有的数据,而且重做日志能够无线的增大,那么不需要将缓冲池中的新版本刷新回磁盘。因为发生宕机的时候通过重做日志文件就可以恢复整个数据库系统中的数据到宕机发生的时刻。但是这需要两个条件:1.缓冲池可以缓存数据库所有的数据,2.重做日志能够无限增大。这几乎是不可能的(原因就不说了...),而且就算满足条件,宕机数据库恢复的时间会非常久。(说到底,就是得用Checkpoint技术,实现分批定时将数据刷新到磁盘)

Checkpoint(检查点)技术目的是解决如下问题:

  • 缩短数据库的恢复时间;当发生宕机时,数据库不需要重做所有的日志,因为Checkpoint之前的页都已经刷新到磁盘。
  • 缓冲池不够用时,将脏页刷新到磁盘;当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,那么需要强制执行Checkpoint,将脏页也就是新版本刷回磁盘。
  • 重做日志不可用时,刷新脏页。所谓的不可用,是指重做日志的设计是循环使用的,并不是让其无限增大的,重做日志可以被重用的部分是指这些重做日志已经不再需要(应该是已经被刷回到磁盘),发生宕机时,恢复操作不需要这部分重做日志,因此这部分可以被覆盖重用,也即是上面说的重做日志不可用,但是如果想要使用不可用的重做日志,就需要强制使用Checkpoint,将缓冲池中的页至少刷新到当前重做日志的位置(这里和下面的分析有一些冲突)。

对于InnoDB存储引擎,通过LSN来标记版本的。而LSN是8个字节的数字,每个月有LSN,重做日志有LSN,Checkpoint也有LSN。

通过命令查看LSN。

show engine innodb statusG;
LOG
---
Log sequence number 33646077360
Log flushed up to   33646077360
Last checkpoint at  33646077360
0 pending log writes, 0 pending chkp writes
49687445 log i/o's done, 1.25 log i/o's/second

在InnoDB存储引擎有两种Checkpoint,分别是:

  • Sharp Checkpoint
  • Fuzzy Checkpoint

Sharp Checkpoint发生在数据库关闭时将所有的脏页都刷新回磁盘,这是默认的工作方式,即参数innodb_fast_shutdown = 1。

在内部使用Fuzzy Checkpoint进行页的刷新,即只刷新部分脏页,而不是刷新所有的脏页回磁盘。

可以分为如下一些情况:

  • Master Thread Checkpoint
  • FLUSH_LRU_LIST_Checkpoint
  • Async/Sync Flush Checkpoint
  • Dirty Page too much Checkpoint

对于Master Thread Checkpoint,差不错以每秒或者每十秒的速度从缓冲池的脏页列表中刷新一定比例的页回磁盘。这个过程是异步的,即此时InnoDB可以进行其他操作。

FLUSH_LRU_LIST_Checkpoint是因为InnoDB需要保证LRU列表中需要有差不多100个空闲页可使用。如果没有100个空闲页,那么InnoDB会将LRU列表尾端的页移除。如果这些页中有脏页,那么需要进行Checkpoint,而这些页来自LRU列表。从MySql 5.6版本开始,这个检查工作被放在一个单独的Page Cleaner线程中进行,并且用户可以通过参数innodb_lru_scan_depth控制LRU列表中可用页的数量,默认为1024。

Async/Sync Flush Checkpoint指的是重做日志不可用的情况,这是需要强制将一些页刷新回磁盘(这里和上面的分析有一些冲突,希望可以交流学习),而此时是从脏页列表中选取的。这包含一系列的触发的判断条件,目的是为了保证重做日志的循环使用的可用性。在InnoDB 1.2.x版本之前,Async Flush Checkpoint会阻塞发现问题的用户查询线程,而Sync Flush Checkpoint会阻塞所有的用户查询线程,并且等待脏页刷新完成。从InnoDB 1.2.x版本以后,也就是MySQL 5.6版本,这部分被放到单独的Page Cleaner Thread中,不会阻塞用户查询线程。

最后一种Checkpoint的情况是Dirty Page too much,即脏页数据太多,导致强制执行Checkpoint。其目的是保证缓冲池中有足够可用的页,由参数innodb_max_drity_pages_pct控制,目前默认值75,即75%。

转载请注明出处。
作者:wuxiwei
出处:http://www.cnblogs.com/wxw16/p/6222624.html

原文地址:https://www.cnblogs.com/wxw16/p/6222624.html