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

    技术2022-05-20  64

    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

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


    最新回复(0)