MySQL 技术内幕: InnoDB存储引擎——读书笔记(二)

来源:互联网 发布:python循环 编辑:程序博客网 时间:2024/05/30 22:49

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组成。伪代码如下:

  1. void master_thread()
  2. {
  3.     goto loop
  4. loop:    //主循环
  5. /*每1秒钟的操作*/
  6. for ( int i = 0; i < 10; i ){
  7.     thread_sleep( 1 )//sleep 1 second
  8.     do log buffer flush to disk    //刷新日志缓存到磁盘
  9.     if ( last_one_second_ios < 5 )    //当前1秒内的IO小于5次,则合并插入缓冲,即将多个插入合并到一个操作中,可减少IO次数
  10.         do merge at most 5 insert buffer
  11.     if ( buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct )    //当前BufferPool中脏页比例超过参数innodb_max_dirty_pages_pct阈值(默认90,即90%),则需进行磁盘同步,将100个脏页写入磁盘
  12.         do buffer pool flush 100 dirty pages
  13.     if ( no user activity )    //当前无用户活动,则转到background loop
  14.         goto backgroup loop
  15. }
  16. /*每10秒钟的操作*/
  17. if ( last_ten_second_ios < 200 )    //过去10秒磁盘IO操作次数小于200次,则刷新100个脏页到磁盘
  18.     do buffer pool flush 100 dirty pages
  19. do merge at most 5 inter buffer    //合并至多5个插入缓冲
  20. do log buffer flush to disk    //将日志缓冲刷新至磁盘
  21. do full purge    //删除最多20个无用的undo页。(为了提供一致 性 读,UPDATE/DELETE时只是在行结构上加了个删除标记,并未真正删除。此处的操作是真正删除此类信息)
  22. if ( buf_get_modified_ratio_pct > 70%)    //检查BufferPool中脏页比例,刷新100个或10个脏页到磁盘
  23.     do buffer pool flush 100 dirty pages
  24. else
  25.     do buffer pool flush 10 dirty pages
  26. do fuzzy checkpoint    //产生检查点。InnoDB会根据检查点将最旧日志序列号的脏页写入磁盘,保证性能
  27. goto loop
  28. background loop:
  29. do full purge    //删除无用的undo页
  30. do merge 20 insert buffer    //合并20个插入缓冲
  31. if not idle
  32.     goto loop
  33. else
  34.     goto flush loop
  35. flush loop:    //不断刷新100个脏页到磁盘,直到符合条件
  36. do buffer pool flush 100 dirty pages
  37. if ( buf_get_modified_ratio_pct > innodb_max_dirty_pages_pct )
  38.     goto flush loop
  39. goto suspend loop
  40. suspend loop:    //挂起master thread,等待事件发生
  41. suspend_thread()
  42.     waiting event
  43. goto loop
  44. }

潜在问题:

  • 每次刷新固定数目的页到磁盘,限制了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时,只需在配置文件中设置:

  1. [mysqld]
  2. ignore-builtin-innodb
  3. plugin-load=innodb=ha_innodb_plugin.so
  4.    ;innodb_trx=ha_innodb_plugin.so
  5.    ;innodb_locks=ha_innodb_plugin.so
  6.    ;innodb_cmp=ha_innodb_plugin.so
  7.    ;innodb_cmp_reset=ha_innodb_plugin.so
  8.    ;innodb_cmpmem=ha_innodb_plugin.so
  9.    ;innodb_cmpmem=ha_innodb_plugin.so

注:如若涉及版权或者其他问题,请联系本人。

原创粉丝点击