InnoDB学习日记

来源:互联网 发布:周笔畅淘宝店服装 编辑:程序博客网 时间:2024/05/20 13:15

声明:该学习笔记参照《MySQL技术内幕 InnoDB存储引擎 第二版》整理而成。

  1. InnoDB简介:

InnoDB是事务安全的MySQL存储引擎,InnoDB存储引擎是OLTP(在线事务处理)应用中核心表的首选存储引擎。

InnoDB存储引擎最早由InnobaseOy公司开发。该存储引擎是第一个完整支持ACID事务的MySQL引擎,其特点是行锁设计,支持MVCC(多版本并发控制)、支持外键,提供一致性非锁定读,能有效利用内存和CPU。

InnoDB版本介绍:
这里写图片描述

2 . InnoDB体系架构:

这里写图片描述

如图所示,InnoDB有多个内存块,而这些内存块的作用如下:

  • 维护所有进程/线程需要访问的多个内部数据结构
  • 缓存磁盘上的数据,方便快速的读取,在对磁盘文件的数据进行修改之前先在此缓存
  • redo log 缓冲

而后台线程的作用是:负责刷新内存池中的数据,保证缓存池中的数据是最新的数据。并且将已经修改的数据文件刷新到磁盘文件,同时保证在数据库发生异常的情况下InnoDB能恢复到正常的运行状态。

2.1 后台线程介绍:

后台线程1—Master Thread:

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

后台线程2—IO Thread:

InnoDB中大量使用了AIO(Async IO)来处理IO请求,IO Thread主要负责这些IO请求的回调。IO Thread共有4类Thread,分别是:write、read、insert buffer、log IO Thread。
可以使用如下命令查看IO Thread的运行情况:

SHOW VARIABLES LIKE 'innodb_%io_threads';

InnoDB 1.0版本之后,可以通过设置innodb_read_io_threads和innodb_write_io_threads的值来设置write和read线程的数量。

后台线程3—Purge Thread:

事务提交后,其所使用的undolog可能不再需要,因此需要Purge Thread来回收已经使用并分配的undo页。InnoDB 1.1之前,purge操作仅能在Master Thread中完成,从InnoDB 1.1开始,purge操作可以独立到单独的线程中进行操作。用户可以在mysqld配置文件中设置启用独立Purge Thread:

innodb_purge_threads = 1

从InnoDB 1.2之后,支持设置多个Purge Thread。

后台线程4—Page Cleaner Thread:

在 InnoDB 1.2.x 版本中引入,目的是将之前刷新脏页的工作放到单独的线程中去做,以减少Master
Thread的工作及对用户查询线程的阻塞。

2.2 缓冲池
InnoDB 存储引擎是基于磁盘存储的,但由于CPU与磁盘间速度的巨大差距,性能较差。因此引入缓冲池来提高数据库的整体性能。
通过下面命令可以查看当前InnoDB 的缓冲池大小:

SHOW VARIABLES LIKE 'innodb_buffer_pool_size';

InnoDB 中内存的结构如下:
这里写图片描述

缓冲池可以包含若干缓冲池实例,而每个缓冲池实例有包含若干页,每个页根据哈希值平均分配到每个缓冲池实例中。所以缓冲池实例可以理解为内存块。而缓冲池实例的大小可以通过下面命令查看:

SHOW VARIABLES LIKE 'innodb_buffer_pool_instances';

可以运行下面的命令来查看各个缓冲池的使用状态:

SELECT POOL_ID, POOL_SIZE, FREE_BUFFERS, DATABASE_PAGES FROM INNODB_BUFFER_POOL_STATUS';

缓冲池中页的大小默认为16KB。通过LRU算法对缓冲池进行管理。InnoDB的LRU算法设置了一个midpoint位置,大概在3/8处,最近使用的页不是放在两端,而是放在midpoint处,以防止有些热点页被错误的当做不活跃页而被置换出去。

重做日志缓冲区(redo log buffer):

InnoDB首先将重做日志信息先放到重做日志缓冲区,而后按照一定频率,将其刷新到重做日志文件里。重做日志缓冲区不需要很大,通常刷新数据到日志文件的频率为1s,默认大小为8M,可通过下面命令查看:

SHOW VARIABLES LIKE 'innodb_log_buffer_size';

重做日志会在下面的三种情况下将缓冲池的内容刷新到重做日志文件:

  • Master Thread每一秒将做一次缓冲区到磁盘的刷新;
  • 每个事务提交以后将做一次缓冲区到磁盘的刷新;
  • 当重做日志缓冲池的剩余的空间小于总空间的1/2时,将做一次缓冲区到磁盘的刷新;

额外的内存池:

InnoDB通过内存堆来管理内存,分配给数据结构本身的内存空间是从额外的内存池申请的。例如每个缓冲池中的帧缓冲和相应的缓冲控制对象(记录了如LRU、锁、等待等信息)所占用空间是从额外的内存池申请的。所以当InnoDB申请了很大的缓冲池后,应该相应的增大额外缓冲池的大小。

CheckPoint(检查点)技术:

如果每个页改变时,都需要将修改信息写入磁盘,那么数据库的整体性能就会降低,尤其是在热点页在不断更新的情况下。所以当前的事务数据库普遍采用一种Write Ahead Log策略,即在事务提交时,先写重做日志,再将数据更新到磁盘,这样如果机器意外宕机,就可以根据重做日志对数据进行恢复,保证不会丢失数据。如果缓冲池能足够大,并且重做日志也可以无限增大,那么就不需要将新页刷新到磁盘。但是显然上述两个条件很难满足,因此引入检查点技术,检查点的工作如下:

  • 缩短数据库的恢复时间;
  • 缓冲池不够用时,将脏页刷新到磁盘;
  • 重做日志不可用时,刷新脏页;

CheckPoint有两种:

  • Sharp CheckPoint;
  • Fuzzy CheckPoint;

Sharp CheckPoint发生在数据库关闭之前,这种策略会将全部脏页都刷新到磁盘,如果此时有其他的线程在运行,则会被阻塞,从而对数据库的性能造成很大的影响。而 Fuzzy CheckPoint只是刷新部分脏页到磁盘。

而Fuzzy CheckPoint又分为以下四种情况:

  • Master Thread CheckPoint:

以每秒或每10秒从缓冲池按照一定的比例刷新脏页到磁盘,过程是异步的,不会阻塞其他操作。

  • FLUSH_LRU_LIST CheckPoint:

InnoDB需要保证有100个空闲页可供使用,如果没有这么多,InnoDB会将LRU尾端的页移除,如果这些页中有脏页,则需要进行CheckPoint。

  • Async/Sync Flush CheckPoint:

重做日志不可用的情况下,需要强制将一些页刷新回磁盘,而此时的脏页是从脏页列表中选取的。如果将已经写入重做日志文件而没有写入磁盘的页数记为checkpoint_age,将所有重写日志大小记为total_redo_log_file_size,则当checkpoint_age<75%*total_redo_log_file_size时,不需要刷新脏页到磁盘,如果checkpoint_age在total_redo_log_file_size的75%到90%之间时,则采用异步刷新刷新脏页到磁盘使得checkpoint_age<75%*total_redo_log_file_size。

  • Dirty Page too much CheckPoint:

缓冲池中最大脏页数的百分比可以通过下面语句查看:
SHOW VARIABLES LIKE 'max_dirty_pages_pct' \G;
当脏页数在缓冲池中占据75%以上时,会强制进行CheckPoint。

2.3 Master Thread的工作方式

Master Thread具有最高线程优先级。其内部由多个循环组成:主循环(loop)、后台循环(background loop)、刷新循环(flush loop)和暂停循环(suspend loop)。下面用伪代码来说明每个循环的作用:

主循环(loop):

这里写图片描述

可以看到其中包含 1s 的操作和 10s 的操作。

这里写图片描述

这里写图片描述

后台循环(background loop):

这里写图片描述

这里写图片描述
这里写图片描述

从 InnoDB 1.0.x 版本开始,Master Thread 工作逻辑如下:
这里写图片描述
这里写图片描述

InnoDB 1.2.x 版本以后,对 Master Thread 所做的改动为:
这里写图片描述
其中,srv_master_do_idle_tasks 是之前的每 10s 一次的操作,srv_master_do_active_tasks 是之前的每 1s 一次的操作。而每次对 Master Thread 所进行的优化,都有效的提高了InnoDB的性能。

0 0
原创粉丝点击