Mysql 优化之 buffer pool 设置

介绍

Buffer pool是内存中用来缓存数据和索引的存储区域,其是MySQL性能调优的重要一环。 理想情况下,设置的size越大,则缓存到内存的数据越多,InnoDB就越像是内存数据库。 

以便于以后在查询的时候,万一你要是内存缓冲池里有数据,就可以不用去查磁盘了,我们看下图。

Mysql 优化之 buffer pool 设置_第1张图片
Buffer pool的底层是一个列表,通过LRU算法进行数据页的换进换出操作。当空间原因导致新页的加入需要换出一页时,InnoDB取出最近最少使用的页并将这个新的数据页加入到列表的中央。从方向上看,列表的头部是最常使用的数据页,而在尾部则是最少使用的数据页。

思考:生产环境中应该给buffer pool设置多少内存?

首先考虑第一个问题,我们现在数据库部署在一台机器上,这台机器可能有个8G、16G、32G、64G、128G的内存大 小,那么此时buffer pool应该设置多大呢?

有的人可能会想,假设我有32G内存,那么给buffer pool设置个30GB得了,这样的话,MySQL大量的crud操作都是 基于内存来执行的,性能那是绝对高!

毋庸置疑这肯定是错的,你要知道,虽然你的机器有32GB的内存,但是你的操作系统内核就要用掉起码几个GB的 内存! 然后你的机器上可能还有别的东西在运行,是不是也要内存?然后你的数据库里除了buffer pool是不是还有别的内存 数据结构,是不是也要内存?

所以上面那种想法是绝对不可取的! 如果你胡乱设置一个特别大的内存给buffer,会导致你的mysql启动失败的,他启动的时候就发现操作系统的内存根本 不够用了!

所以通常来说,我们建议一个比较合理的、健康的比例,是给buffer pool设置你的机器内存的50%~60%左右 比如你有32GB的机器,那么给buffer设置个20GB的内存,剩下的留给OS和其他人来用,这样比较合理一些。 假设你的机器是128GB的内存,那么buffer pool可以设置个80GB左右,大概就是这样的一个规则。 

配置大小
InnoDB buffer pool的大小可以在启动时配置,也可以在启动之后配置。

参数

  • innodb_buffer_pool_size:缓存区域的大小。
  • innodb_buffer_pool_chunk_size:当增加或减少innodb_buffer_pool_size时,操作以块(chunk)形式执行。块大小由innodb_buffer_pool_chunk_size配置选项定义,默认值128M。可以自行设定,且增加和减少都要以M为单位,并只能在启动前修改,修改后的值
  • innodb_buffer_pool_instances:当buffer pool比较大的时候(超过1G),innodb会把buffer pool划分成几个instances,这样可以提高读写操作的并发,减少竞争。读写page都使用hash函数分配给一个instances。把需要缓冲的数据hash到不同的缓冲池中,这样可以并行的内存读写。innodb_buffer_pool_instances 参数显著的影响测试结果,特别是非常高的 I/O 负载时。

注:增加和减少buffer pool的大小都是以大块的方式,块的大小由参数innodb_buffer_pool_chunk_size决定,默认为128M。
Innodb_buffer_pool_size的大小可以自行设定,但必须是innodb_buffer_pool_chunk_size 乘以 innodb_buffer_pool_instances的整数倍,如果不是,则buffer pool会被调整成大于设定值且最接近的一个值,如下例:

默认 128MB * 16 = 2048 MB (2G) 但是 buffer_pool_size = 9G ,不是整倍数,因此调整为10G

Mysql 优化之 buffer pool 设置_第2张图片
Innodb_buffer_pool_chunk_size*innodb_buffer_pool_instances不能大于buffer pool的大小,否则修改无效。

达到的效果如下:

Mysql 优化之 buffer pool 设置_第3张图片 

小总结:

我们再来做一点总结,就是说你的数据库在生产环境运行的时候,你必须根据机器的内存设置合理的buffer pool的大 小,然后设置buffer pool的数量,这样的话,可以尽可能的保证你的数据库的高性能和高并发能力。

然后在线上运行的时候,buffer pool是有多个的,每个buffer pool里多个chunk但是共用一套链表数据结构,然后执 行crud的时候,就会不停的加载磁盘上的数据页到缓存页里来,然后会查询和更新缓存页里的数据,同时维护一系列 的链表结构。 然后后台线程定时根据lru链表和flush链表,去把一批缓存页刷入磁盘释放掉这些缓存页,同时更新free链表。

如果执行crud的时候发现缓存页都满了,没法加载自己需要的数据页进缓存,此时就会把lru链表冷数据区域的缓存页 刷入磁盘,然后加载自己需要的数据页进来。


上面是最常用的优化手段,下面是一些介绍,可以作为了解:

配置多个buffer pool实例 nnodb_buffer_pool_instances 

当buffer pool的大小是GB级别时,将一个buffer pool分割成几个独立的实例能降低多个线程同时读写缓存页的竞争性而提高并发性。通过innodb_buffer_pool_instances参数可以调整实例个数。如果有多个实例,则缓存的数据页会随机放置到任意的实例中,且每个实例都有独立的buffer pool所有的特性。
Innodb_buffer_pool_instances的默认值是1,最大可以调整成64。

Making the Buffer Pool Scan Resistant

新读取的数据页被插入到buffer pool的LRU列表的中间位置,默认位置是从尾部开始算起的3/8的位置。当被放入buffer pool的页被第一次访问时就开始往列表的前方移动,而这样列表的后部就是不经常访问的页甚至是从不访问的页。
通过参数innodb_old_blocks_pct可以控制列表中”old”数据页所占的百分比,默认是37%,等同于3/8,取值范围是5~95。
Innodb_old_blocks_time参数默认是1000毫秒,指定了页面读取到buffer pool后但没有移动到经常被访问列表位置的时间窗口。

InnoDB buffer pool预存取(read-ahead) 

Read ahead是异步地预先获取多个数据页到buffer pool的IO操作,这些数据页都是假定会随后被用到的。InnoDB通过两种read-ahead算法提高IO性能:
线性read ahead:预测哪些页会被顺序访问。通过innodb_read_ahead_threshold参数调整顺序数据页的数量。当从一个区中顺序读取的页数量大于等于innodb_read_ahead_threshold时,innodb会触发异步read ahead操作将真个区都读到buffer pool中。该参数的默认值是56,取值范围是0~64。
随机read ahead:通过已经在buffer pool中的数据页来预测哪些页会被随后访问到。如果13个连续的处于相同区的页存在于buffer pool中,则InnoDB会把同一个区的其它页都读取进来。通过设置innodb_random_read_ahead=ON来开启此方式。
通过执行show engine innodb status命令显示的三个参数判断read-ahead算法的有效性:
Innodb_buffer_pool_read_ahead
Innodb_buffer_pool_read_ahead_evicted
Innodb_buffer_pool_read_ahead_rnd

InnoDB buffer pool flushing配置 

Innodb会在后台将buffer pool中的脏页(已经修改但没有写到数据文件)flush掉。当buffer pool中的脏页所占百分比达到innodb_max_dirty_pages_pct_lvm会触发flush,当所占比例达到innodb_max_dirty_pages_pct时,则innodb会“强烈”的flush。
针对数据修改操作频繁的系统,flush可能会严重滞后导致有大量的buffer pool内存占用,有一些参数专门针对修改繁忙的系统可以调整:
Innodb_adaptive_flushing_lwm:为防止redo log被填满,此参数设置一个阈值,如果redo log的容量超过此阈值,则执行adaptive flush操作。
Innodb_max_drity_pages_pct_lwm
Innodb_io_capacity_max
Innodb_flushing_avg_loops

重置buffer pool状态 

InnoDB可以通过配置innodb_buffer_pool_dump_at_shutdown参数来确保在mysql正常重启时部分经常使用的数据页能直接加载到buffer pool中,通过批量加载的方式,以节省重启mysql导致的warmup时间(原先在buffer pool中的数据页要从磁盘再次加载到内存中)。
Buffer pool的状态可以在任意时刻被保存,而重置状态也可以恢复任意保存的副本。
在数据库运行期间动态配置buffer pool数据页保留占比的方式是:
SET GLOBAL innodb_buffer_pool_dump_pct=40;

而在配置文件中的配置方法为:

[mysqld]
innodb_buffer_pool_dump_pct=40
配置当服务器关闭时保存buffer pool的当前状态的方法是:
SET GLOBAL innodb_buffer_pool_dump_at_shutdown=ON;
当服务器开启时重新加载buffer pool的方法是:
mysqld --innodb_buffer_pool_load_at_startup=ON;
默认情况下innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup两个配置是开启状态
在关闭MySQL时,会把内存中的热数据保存在磁盘里ib_buffer_pool文件中,位于数据目录下。

数据库运行期间保存和重新加载buffer pool的方法是:
SET GLOBAL innodb_buffer_pool_dump_now=ON;
SET GLOBAL innodb_buffer_pool_load_now=ON;

查看buffer pool保存和重新加载的进度的方法是:
mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status';

监控buffer pool的状态情况
通过show engine innodb status命令可以查看buffer pool的运行情况

你可能感兴趣的:(数据库,mysql)