2.1 InnoDB体系结构
主要由后 台线程、内存池构成,主要负责进程/线程的内 部数据结构、缓存数据、redo log等工作。(通过 show engine innodb status/G 查看运行情况)
1. 后 台线程
默认情况下,有7个:4个IO thread,1个master thread,1个锁监控线程,1个错误监控线程 。IO thread数量由my.cnf中的innodb_file_io_threads参数控制(默认为4,linux下不可调整。InnoDB Plugin中,read thread、write thread分别由参数innodb_read_io_threads、innodb_write_io_threads控制,且均增大到了4个)
2. 内存
包括buffer pool、redo log buffer和additional memory pool,分别由参数innodb_buffer_pool_size、innodb_log_buffer_size及 innodb_additional_mem_pool_size调整。
InnoDB工作方式 :将数据文件按页(每 页16K) 读入InnoDB buffer pool,然后按最近最少使用算法(LRU)保留缓存数据,通过一定频率将脏页刷新到文件。缓存的数据页类型包括:索引页、数据页、undo页、 insert buffer、自 适应 哈希索引、InnoDB锁信息以及数据字典信息等。
InnoDB中,内存的管理是通过 内存堆(heap)的方式进行的。对一些数据结构本身分配内存时,需要从additional memory pool 中申请,不够时则会从buffer pool中申请。当申请的InnoDB buffer pool较大时,additional memory pool大小也应随之增加。
2.2 master thread
优先级最高,由主循环(loop)、background loop、flush loop和suspend loop组成。伪代码如下:
- void master_thread()
- {
- goto loop
- loop: //主循环
- /*每1秒钟的操作*/
- for ( int i = 0; i < 10; i ){
- thread_sleep( 1 ) //sleep 1 second
- do log buffer flush to disk //刷新日志缓存到磁盘
- if ( last_one_second_ios < 5 ) //当前1秒内的IO小于5次,则合并插入缓冲,即将多个插入合并到一个操作中,可减少IO次数
- do merge at most 5 insert buffer
- if ( buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct ) //当前BufferPool中脏页比例超过参数innodb_max_dirty_pages_pct阈值(默认90,即90%),则需进行磁盘同步, 将100个脏页写入磁盘
- do buffer pool flush 100 dirty pages
- if ( no user activity ) //当前无用户活动,则转到background loop
- goto backgroup loop
- }
- /*每10秒钟的操作*/
- if ( last_ten_second_ios < 200 ) //过去10秒磁盘IO操作次数小于200次,则刷新100个脏页到磁盘
- do buffer pool flush 100 dirty pages
- do merge at most 5 inter buffer //合并至多5个插入缓冲
- do log buffer flush to disk //将日志缓冲刷新至磁盘
- do full purge //删除最多20个无用的undo页。(为了提供一致 性 读,UPDATE/DELETE时只是在行结构上加了个删除标记,并未真正删除。此处的操作是真正删除此类信息)
- if ( buf_get_modified_ratio_pct > 70%) //检查BufferPool中脏页比例,刷新100个或10个脏页到磁盘
- do buffer pool flush 100 dirty pages
- else
- do buffer pool flush 10 dirty pages
- do fuzzy checkpoint //产生检查点。InnoDB会根据检查点将最旧日志序列号的脏页写入磁盘,保证性能
- goto loop
- background loop:
- do full purge //删除无用的undo页
- do merge 20 insert buffer //合并20个插入缓冲
- if not idle
- goto loop
- else
- goto flush loop
- flush loop: //不断刷新100个脏页到磁盘,直到符合条件
- do buffer pool flush 100 dirty pages
- if ( buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct )
- goto flush loop
- goto suspend loop
- suspend loop: //挂起master thread,等待事件发生
- suspend_thread()
- waiting event
- goto loop
- }
潜在问题:
- 每次刷新固定数目的页到磁盘,限制了InnoDB在固态磁盘下IO写入性能;写应 用频繁时,master thread可能会得不到及时地将数据刷新至磁盘,同时宕机时会增加recovery时间。解决方法:InnoDB Plugin中通过innodb_io_capacity 控制磁盘IO吞吐量,默认200。刷新数据时,会按 innodb_io_capacity的百分比刷新相对数量的页。规则如下:合并插入缓冲时,合并插入缓冲的数目为innodb_io_capacity 的5%;刷新脏页时,刷新数目为innodb_io_capacity。
- innodb_max_dirty_pages_pct 默认值 由90%变为了75%。加快了脏页刷新频率减少恢复时间,也可保证磁盘IO负载。
- innodb_adaptive_flushing(自 适应刷新) ,影响每秒刷新脏页的数目。规则由原来的“大于innodb_max_dirty_pages_pct时刷新100个脏页到磁盘”变为 “通过buf_flush_get_desired_flush_reate函数判断重做日志产生速度确定需要刷新脏页的最合适数目”;即使脏页比例小于 innodb_max_dirty_pages_pct时也会刷新一定量的脏页。
(随着这三个潜 在 问题的解决,master thread伪码也在日志刷新部分做了些调整,这里不再列举,详情可参考该书。)
2.3 关键特性
1. insert buffer :性 能
insert buffer和数据页一样,也是物理页的一个组成部分。应用程序中行记录的insert顺序是按主键递增插入的(主键是行的唯一标识),故插入聚集索引一 般是顺序的。在插 入 操作时,数据页的存放是按主键执行顺序存放,对于非聚集索引(secondary index),叶子节点的插入就不是按顺序的了,此时需离散地访问非聚集索引页。B+树的特性决定了非聚集索引插入的离散性。
对于 非聚集索引的插 入和更新,不是每次都直接 插 入索引页,而是先判断插 入的索引页是否在缓冲池。如果在,便插 入 缓冲池;否则,先放入一个插 入缓冲区,然后以一定频率执行插 入缓冲和非聚集索引页节点的合并操作,合并在一个索引页上的插 入 操作,最后一起刷新至磁盘。
需满足两个条件:secondary index且不是唯一索引 (不用检查唯一情 况)
插入缓冲最大可占1/2的缓冲池内存,此时会对其他操作带来一定影响。
2.double write : 可靠性
重做日志中记录的是对页的物理操作,若此页损坏,则会导致数据丢失。
doublewrite由两部分组成:内存中的doublewrite buffer(2M)和物理磁盘共享表空间中连续的两个区(128个页,也是2M)。
当缓冲池脏页刷新时,并不直接写磁盘,而是通 过memcpy函数将脏页拷贝至内存中的doublewrite buffer,然后通过doublewrite buffer分两次、每次1M写入共享表空间的物理磁盘上;之后调用fsync函数同步磁盘。完成doublewrite页写入后,再将 doublewrite buffer相关页写入各个表空间文件(此时写入是离散的)。
--skip_innodb_doublewrite可禁用两次写功能,不过可能会导致写失效问题。
3.自适应哈希索引
InnoDB会监控表上索引的查找,根据访问频率和模式为某些页建立哈希索引提高查询性能。由InnoDB自动实现的,通过缓冲池的B 树构建而来。设计思想是数据库自优化。(哈希一般情况下查找时间复杂度为O(1),常用于JOIN操作。但只能用于等值查询 。)
2.4 启动、关闭和恢复
innodb_fast_shutdown 影响InnoDB表关闭情况。
0:MySQL关闭时,需完成 所有的full purge和merge insert buffer操作。
1:默认值,只将缓冲池内的一些脏页刷新至磁盘。
2:将日志 都写入日志文件,不会有任何事务丢失,但下次启动时会进行recovery。
innodb_force_recovery 影 响InnoDB的恢复状况。默认为0,表示需恢复时执行所有的恢复操作。若不能有效恢复,则MySQL有可能宕机,错误信息会被写入错误日志文件。还有 1~6等值,详细内容可参考本书。
想使用新的InnoDB Plugin引擎 ,而非builtin InnoDB时,只需在配置文件中设置:
- [mysqld]
- ignore-builtin-innodb
- plugin-load=innodb=ha_innodb_plugin.so
- ;innodb_trx=ha_innodb_plugin.so
- ;innodb_locks=ha_innodb_plugin.so
- ;innodb_cmp=ha_innodb_plugin.so
- ;innodb_cmp_reset=ha_innodb_plugin.so
- ;innodb_cmpmem=ha_innodb_plugin.so
- ;innodb_cmpmem=ha_innodb_plugin.so
注:如若涉及版权或者其他问题,请联系本 人。