标签:相关 manual style 建议 一段 维护 engine 第一部分 配置文件
InnoDB通过在内存中维护缓存池(Buffer Pool)来对数据和索引进行缓存,从而提高数据库性能。了解Mysql内存缓冲池的原理,并针对性地进行调优,能够最大化其带来的性能优势。
通常,在保证服务器上其他应用程序有足够内存的情况下,可以给buffer pool分配尽可能多的内存空间。越大的buffer pool能够使mysql越能够像内存数据库一样提供服务。其大小通过innodb_buffer_pool_size配置。对于64 bit 机器,可以将buffer pool 配置为多个部分,以降低并发操作情况下的资源争用。
InnoDB buffer pool的状态及使用情况可以通过 SHOW ENGINE INNODB STATUS 命令得到,相关信息位于 BUFFER POOL AND BUFFER 区。
InnoDB 将buffer pool作为一个list, 采用LRU算法的变体进行维护。当需要向pool中添加新内存分页(page)时,InnoDB会按照LRU原则丢弃一个旧的page,并向list的中间插入新的page。这种方法将list作为两个sublist:
此算法保证,那些最近被频繁读取的page位于new list中,而读取时间较远的page位于old list中,可能会被淘汰。
默认地,LRU 算法运行机制如下:
buffer pool主要的配置参数如下:
将该参数设定为大于0,可以避免仅读取一次的查询过度占用buffer pool的新生代。那些仅被读取一次的内存分页会随着时间的推移,逐渐从老年代中移出。而对于需要进行buffer pool预热的情形,则建议将该参数设定为0,以保证读取的数据能够及时移动至新生代。该参数可以在运行时进行设置,对于那些需要全表扫描或者进行数据备份的场景,可以临时将该参数设定为较大的数值,以避免临时操作对buffer pool使用带来明显的占用和影响。
对于可以将InnoDB 的buffer pool设置为上G的场景,建议将buffer pool配置为多个实例。对应的控制参数已在第一部分进行了介绍。
其原因主要是,在buffer pool容量较大的情况下,许多查询请求都会从buffer pool中获取数据,高并发会带来额外的并发资源维护代价。而将buffer pool 配置为多个实例,InnoDB 保证每个buffer pool其运行完全独立,受独立的信号量控制。被读入buffer pool中的内存分页通过hash随机分配至某个实例中。配置多buffer pool的情况下,建议通过size 及instances 参数的组合,保证每个实例的内存空间大于1G。
InnoDB 并没有使用经典的LRU算法管理buffer pool,为了应对可能发生的低频扫描式查询长时间大量占用宝贵的内存资源,InnoDB将buffer pool分为两个区域,新生代和老年代来管理,并且引入old_blocks_pct 和 old_blocks_time 两个参数来允许用户结合自己的使用场景对buffer pool进行配置,以最大化合理利用buffer pool。
如第2节所述,old_blocks_time控制了内存分页被首次读取后必须留在老年代的时间,通过这种控制,有效避免了那些可能出现的“假热”数据一开始就位于buffer pool的头部,此后需要较长时间才能从buffer pool中移除。那些仅读取一次的数据,既然不是热点,一开始限制其位于老年代区,主要带来两个方面的益处:a. 降低其呆在buffer pool中的时间;b. 降低其“权重”,避免可能由于其占用空间过大,而将真正的热点数据挤出buffer pool。
事实上,我认为这里如果想做更加精细的控制,可以映入old_blocks_access_times(将其从老年代移入新生代前必须经过的访问次数),这样,用户可以结合实际的场景取得更加全面的控制。
old_blocks_pct 和 old_blocks_time 两个参数均可以实现动态配置。用户可以结合自己的实际,在不同的使用场景下进行临时配置。总的来说,当不希望大量扫描性的数据侵占buffer pool空间时,可以将pct参数设置较低。而当场景中涉及到的表规模都不大时,可以适当放大pct参数。time参数则需要经过仔细的模拟测试,选择适合应用场景的值。
当InnoDB 判断位于同一个内存分区(extent)(一个内存分区由64个内存分页组成)的数据可能将要被读取时,将会对该分区的所有数据进行异步预读取,该预读取将一个分区中不在buffer pool中的内存分页一次性全部读取到pool中。数据预读取技术也是为了提高Mysql的I/O表现。有两种预读取方式:
第一种是线性读取。主要针对顺序读取内存分区中若干分页的情况,触发线性读取的时机由innodb_read_ahead_threshold控制,其值可以设置为0-64中的任一值N,表示当顺序读取位于同一分区的N个分页后,InnoDB会将该分区中的其他数据读取至pool中,该值的默认数值是56。
第二种是随机读取。是指当内存分区中的13个连续的分页被读取至buffer pool后,InnoDB会将该内存分区中的其他分页也读取至pool中。该读取方式由开关参数 innodb_read_ahead_random控制,设置为ON表示启用该预读取方式。
对于在 buffer pool 中发生改变而未同步至数据文件中的数据,InnoDB称之为脏页(dirty-pages)。InnoDB 在 buffer pool 正常运行的同时,以守护的方式将 dirty pages 刷新至磁盘。
刷新的时机由两个参数决定:innodb_max_dirty_pages_pct(默认值为75) 和 innodb_max_dirty_pages_pct_lwm (lwm 表示 low water mark, 低水位)。当dirty pages 达到 innodb_max_dirty_pages_pct_lwm 规定的值时,InnoDB开始刷新磁盘。当dirty pages 达到 innodb_max_dirty_pages_pct 时,InnoDB会以更快的速率执行flushing(位于innodb_io_capacity与innodb_io_capacity_max之间)。
InnoDB 以循环利用的方式管理其日志。在重复使用某一段redo log前,InnoDB 会先将记录在此段redo log但未写入磁盘的记录从buffer pool中刷新至磁盘,从而可能导致I/O性能的短暂突降,此种场景称之为sharp checkpoint。对于写入负载较高的应用场景,sharp checkpoint 可能容易发生,即使当前buffer pool 中的脏页未达到innodb_max_dirty_pages_pct。
InnoDB 基于当前 flushing 的速率以及 redo log 生成的速率估计需要的 flushing 速率,其目的主要是保证当前buffer pool 中有足够可用空间的同时,避免由于 flushing 导致的I/O性能突降。当以较高的速率执行 flushing 时,I/O 可能大部分被其占用,而应用触发的读写得不到及时响应,从而表现出性能突降。
这种自适应的算法能够处理诸如负载突然发生变化的场景。该机制由参数innodb_adaptive_flushing控制,默认为打开状态(ON),可以在运行时或者配置文件中进行动态配置。此算法并不适用于所有场景,对于频繁写入,redo log 经常被写满的情况更加适合。
自适应刷新磁盘还受如下参数的影响:
除此之外,InnoDB 还提供如下两个参数,实现对flushing更加精细的控制:
对于buffer pool较大,在Mysql 启动时需要较长时间进行warm up的情况,InnDB支持在停机时保存Buffer Pool的状态并在下次启动时快速恢复。
【Reference】
1. MySQL 5.6 Reference Manual
标签:相关 manual style 建议 一段 维护 engine 第一部分 配置文件
原文地址:https://www.cnblogs.com/luojiahu/p/11107320.html