2.1 InnoDB 概述
2.2 InnoDB 版本
2.3 InnoDB 体系架构
后台线程的主要作用是负责刷新内存池中的数据, 保证缓冲池中的内存缓存的是最近的数据。 此外将已修改的数据文件刷新到磁盘文件, 同时保证在数据库发生异常的情况下 InnoDB 能恢复到正常运行的状态。
2.3.1 后台线程
1 Master Thread
主线程主要负责将缓冲池中的数据异步刷新到磁盘, 保证数据的一致性, 包括脏页的刷新、合并插入缓冲(Insert Buffer), Undo 页的回收等。
2 IO Thread
IO 线程主要负责 AIO(async IO)请求的回调(call back)处理。 从 InnoDB 1.0.x 开始, read thread 和 write thread 分别增到到了 4 个, 用 innodb_read_io_threads 和 innodb_write_io_threads 参数进行设置。
上图可以看到 IO Thread 0 为 insert buffer thread。 IO Thread 1 为 log thread 。 之后就是 innodb_read_io_threads 及 innodb_write_io_threads 来设置的读写线程, 且 读线程的 ID 总是 小于写线程。
3 Purge Thread
事务被提交后, 其所使用的 undo log 可能不再需要, 因此需要 purge thread 来回收已经使用并分配的 undo 页。 从 Innodb 1.2 版本开始, Innodb 支持多个 purge thread , 这样做的目的是为了进一步加快 undo 页的回收。 同时由于 purge thread 需要离散地读取 undo 页, 这样也能更进一步利用磁盘的随机读取性能。
4 Page Cleaner Thread
作用是将之前版本中脏页的刷新操作都放入到单独的线程中来完成。 目的是为了减轻原 master thread 的工作及对于用户查询线程的阻塞, 进一步提高 Innodb 引擎的性能。
2.3.2 内存
1 缓冲池
Innodb 引擎是基于磁盘存储的, 并将其中记录按照页的方式进行管理。 因此可将其视为基于磁盘的数据库系统。
需要注意, 页从缓冲池刷新回磁盘的操作并不是在每次页发生更新时触发, 而是通过一种称为 checkpoint 的机制刷新回磁盘。 同样是为了提高数据库的整体性能。
缓冲池的配置通过参数 innodb_buffer_pool_size 来设置。
缓冲池中缓冲的数据页类型有: 索引页, 数据页, undo 页, 插入缓冲(insert buffer),自适应哈希索引(adaptive hash index), innodb 存储的锁信息(lock info), 数据字典信息(data dictionary)等.
参数 innodb_buffer_pool_instances 来配置允许有多少个缓冲池实例。
从 mysql 5.6 开始, 通过 information_schema 下的 innodb_buffer_pool_stats 来观察缓冲状态。
2 LRU List, Free List 和 Flush List
通常来说, 数据库中的缓冲池是通过 LRU (Latest Recent Used)算法来管理的。
在 innodb 存储引擎中, 缓冲池页的大小默认为 16KB , 同样用 LRU 算法对缓洪池进行管理。
midpoint insertion strategy: 新读取到的页, 虽然是最新访问的页, 但并不是直接放入到 LRU 列表的首部, 而是放入到 LRU 列表的 midpoint 位置。 默认配置下, 该位置在 LRU 列表长度的 5 / 8 出。 midpoint 位置可由参数 innodb_old_blocks_pct 控制。 innodb_old_blocks_pct 默认值为 37 , 表示新读取的页插入到 LRU 列表尾端的 37% 位置(差不多 3 / 8 处)。 在 Innodb 中, 把 midpoint 之后的列表称为 old 列表, 之前的列表 称为 new 列表。 可以简单理解为 new 列表的页都是最为活跃的热点数据。
参数 innodb_old_blocks_time : 用于表示页读取到 mid 位置后需要等待多久才会被加入到 LRU 列表的热端。
database pages 表示 LRU 列表中页的数量。
pages made young 显示了 LRU 列表中页移动到前端的次数, 若服务器运行阶段没有改变 innodb_old_blocks_time 的值, 则 not young 为 0
modified db pages 显示了脏页的数量。
可通过表 innodb_buffer_page_lru 观察每个 LRU 列表中每个页的具体信息。
在 LRU 列表中页被修改后, 该页为脏页(dirty page), 即缓冲池中的页和磁盘上的页的数据不一致, 这时数据库会通过 checkpoint 机制将脏页刷新回磁盘, 而 flush 列表中的页即为脏页列表。 需要注意, 脏页既存在与 LRU 列表中, 也存在于 Flush 列表中。 LRU 列表用来管理缓冲池中页的可用性, Flush 列表用来管理将页刷新回磁盘。
3 重做日志缓冲
重做日志缓冲一般不需要设置得很大, 因为一般情况下每一秒会将重做日志缓冲刷新到日志文件, 因此用户只需要保证每秒产生的事务量在扎个缓冲大小之内即可。 该值可由 innodb_log_buffer_size 控制, 默认 8MB。
重做日志在下列三种情况下会将重做日志缓冲中的内容刷新到外部磁盘的重做日志文件中:
1 master thread 每一秒将重做日志缓冲刷新到重做日志文件;
2 每个事务提交时会将重做日志缓冲刷新到重做日志文件;
3 当重做日志缓冲池剩余空间小于 1 / 2 时, 重做日志换成刷新到重做日志文件。
4 额外的内存池
2.4 CheckPoint 技术
倘若每次一个页发生变化, 就将新页的版本刷新到磁盘, 这个开销就非常大了, 当前事务数据库系统普遍都采用了 Write Ahead Log 策略, 即当事务提交时, 先写重做日志,再修改页。
checkpoint (检查点)技术的目的是解决一下几个问题:
1 缩短数据库的恢复时间;
2 缓冲池不够用时, 将脏页刷新到磁盘;
3 重做日志不可用是, 刷新脏页。
对 Innodb 引擎而言, 其是通过 LSN(Log Sequence Number) 来标记版本的。
在 Innodb 引擎内, 有两种 checkpoint , 分别为:
1 Sharp Checpoint
2 Fuzzy Checkpoint
Sharp Checkpoint 发生在数据库关闭时将所有的脏页都刷新回磁盘, 这是默认工作方式。
Fuzzy Checkpoint 使用 Fuzzy Checkpoint 进行页刷新, 即只刷新一部分脏页, 而不是刷新所有的脏页回磁盘。
innodb_lru_scan_depth 控制 LRU 列表中可用页的数量, 默认为 1024.
2.5 Master Thread 工作方式
http://www.cnblogs.com/xuanzhi201111/p/4040681.html
主线程逻辑:
2.6 InnoDB 关键特性
2.6.1 插入缓冲 (Insert Buffer)
1 Insert Buffer
Insert Buffer 的使用需要同时满足以下两个条件:
1 索引是辅助索引(secondary index);
2 索引不是唯一的(unique)。
2 Change Buffer
参数 innodb_change_buffering, 用来开启各种 buffer 的选项。 参数可选值: inserts, deletes, purges, changes, all, none.
从 Innodb 1.2.x 开始, 通过 innodb_change_buffer_max_size 来控制 change buffer 最大使用内存的数量。 默认值为 25 , 表示 最多使用 1 / 4 的缓冲池内存空间。需要注意, 该参数的最大有效值为 50.
3 Insert Buffer 的内部实现
Insert Buffer 的数据结构是一颗 B+ 数, 在现在的版本中, 全局只有一棵 Insert Buffer B + 树, 负责对所有表的辅助索引进行 Insert Buffer。 其 非叶子节点存放的是查询的 search key (键值)
4 Merge Insert Buffer
Merge Insert Buffer 的操作可能发生在一下几种情况下:
1 辅助索引页被读取到缓冲池时;
2 Insert Buffer Bitmap 页追踪到该辅助索引页已无可用空间时;
3 Master Thread
2.6.2 两次写 (Double Write)
double write 由两部分组成, 一部分是内存中的 double write buffer, 大小为 2MB; 另一部分是物理磁盘上共享表空间中连续的 128 个页, 即 2 个区, 大小同样是 2MB。
2.6.3 自适应哈希索引 (Adaptive Hash Index)
Innodb 存储引擎会自动根据访问的频率和模式来自动地为某些热点页建立哈希索引。
访问模式一样指的是查询的条件一样, 若交替进行上述查询, 那么 Innodb 引擎不会对该页构造 AHI。
哈希索引 只能用来搜索等值的查询, 如 select *from table where index_col='xxx'. 而对于其他查找类型, 如范围查找, 是不能使用哈希索引的, 因此出现了 non-hash searches / s 的情况。 通过 hash searches:non-hash searches 可以大概了解使用哈希索引后的效率。
2.6.4 异步 IO (Async IO)
2.6.5 刷新临接页 (Flush Neighbor Page)
参数 innodb_flush_neighbors, 用来控制该特性。 对于传统机械硬盘建议启用该特性, 对于固态硬盘有着超高 IOPS 性能的磁盘, 则建议将该参数设置为 0, 即关闭次特性。
2.7 启动、关闭与恢复
参数 innodb_fast_shutdown 影响着表的存储引擎 Innodb 的行为。 参数可取值为 0, 1, 2 , 默认为 1.
为 0 时, 表示数据库关闭时, innodb 需要完成 所有的 full purge 和 merge insert buffer, 并且将所欲的脏页刷新回磁盘。 如果在进行 Innodb 升级时, 必须将这个参数调为 0, 然后再关闭数据库。
为 1 时, 默认值, 表示不需要完成 full purge 和 merge insert buffer 操作, 单是在缓冲池中的一些数据脏页还是会刷新回磁盘。
为 2 时, 不完成 full purge 和 merge insert buffer 操作, 也不将缓冲池中的数据脏页写会磁盘, 而是将日志都写入日志文件。这样不会有任何事物丢失, 单下次 Mysql 启动时, 会进行恢复操作。
需要注意的是, 在设置了参数 innodb_force_recovery 大于 0 后, 用户可以对表进行 select , create 和 drop 操作, 但 Insert ,update 和delete 这类 DML 操作是不允许的。