快速预热Innodb Buffer Pool的方法

2013-09-25  王老虎888

当innodb_buffer_pool_size大到几十GB或是百GB的时候,因为某些日常升级更新或是意外宕机,而必须要重新启动mysqld服务的之后,就面临一个问题,如何将之前频繁访问的数据重新加载回buffer中,也就是说,如何对innodb buffer pool进行预热,以便于快速恢复到之前的性能状态。如果是光靠Innodb本身去预热buffer,将会是一个不短的时间周期,业务高峰时,数据库将面临相当大的考验,I/O的瓶颈会带来糟糕的性能。那么,该怎么办呢?于是大家便想出一些办法,最后Percona把这个需求,在XtraDB中最为一个新特性实现这个功能。

早期,Peter在实际的工作中总结了一些预热buffer pool的SQL语句,也就是通过人为模拟一些请求,尽可能地将我们所需的数据块和索引加载到内存中。

1. 加载主键索引

select count(*) from tbl where no_index_col=0;

2. 加载非主键索引

select count(*) from tbl where index_col like “%0%”;

3. 加载BLOB/TEXT列

select count(*) from tbl where blob_col like “%0%”;

4. 分段加载大表数据

select count(*) from tbl where id between 1 and 10000000 and no_index_col=0;

还有人使用blackhole引擎来进行预热操作,通过替换不同的索引字段进行排序查询,将所需数据加载。

create table temp_blackhole like tbl;

alter table temp_blackhole engine=blackhole;

select * from tbl order by id into temp_blackhole;

现在,Percona已经完全在XtraDB中实现这个功能,最初采用Share Memory Buffer Pool,目前采用Dump/Restore of the Buffer Pool

1. Share Memory Buffer Pool

该方法在内存个划出一个共享段用于存储buffer pool,使得这块空间在mysqld启动关闭前后都能备份访问,不会因为mysqld关闭而将buffer pool的内容清除。但是,共享内存的使用必须遵守严格的要求:innodb引擎前后保持一致;innodb的page页大小前后保持一致;innodb_buffer_pool_size的大小前后保持一致。否则,会遇到问题,这时就不能在使用共享空间,需要手动将其删除。

innodb_buffer_pool_shm_key — 用于是否开启共享内存的使用,0开启,1不开启。

innodb_buffer_pool_shm_checksum — 检查共享空间中存储的buffer pool是否有损坏。

/proc/sys/kernel/shmmax — 内存共享空间的大小可以通过系统下的该文件去调整。

2. Dump/Restore of the Buffer Pool

从名字就可以知道这个预热方法,先将buffer pool的内容dump出来,在数据目录下会生成一个ib_lru_dump的文件,然后需要是再通过这个dump文件将其恢复回去,这也正是我们最初的一个想法。下面简单说下它的实现过程,先需要了解下Innodb buffer pool。

Innodb Buffer Pool是内存中的一段存储空间,由大小为16KB的page页组成,是一个列表页,该列表按照LRU的顺序进行排列,所以也被叫作LRU列表。buffer pool被分成两个子列,前半段被称为’young’,也就是经常被访问到的块,而后半段成为’old’,访问次数较少的块。当有新的块被加载进来的时候,会被插入到两端之间的位置,之后会随着被访问的频繁程度,是保持迁移还是不断后退,最后被替换出去。

在了解了Innodb Buffer Pool之后,让我么来看看dump操作。我们知道磁盘的查找更多是无序的随机的操作,而加载到内存中的page会被重新组织成有序的排列。XTRA_LRU_DUMP的操作并不是简单的将innodb_buffer_pool中的所有内容备份到ib_lru_dump文件中,这样会随着innodb_buffer _pool_size的大小而变得很大,进而备份恢复时间也会变得不很乐观,那么怎么做呢?事实上,只需备份page在buffer pool中的标志信息即可,即(space_id,page_no)这样一个列表,space_id表示page在buffer pool中LRU的排列顺序,page_no表示page在磁盘上的存储位置。恢复时,按照page_no去磁盘中找到对应的page,而这个可以按照page_no的顺序去查找,可以近似看作是顺序i/o,尽量避免随机i/o的消耗,然后将查找到的page按照space_id存到最初在LRU列表中的位置,最后实现恢复到关闭服务之前的状态。这个方法提供了自动和手动两种实现操作。

自动参数设置:

innodb_buffer_pool_restore_at_startup/innodb_auto_lru_dump — 该参数可以控制是否开启自动dump/restore的操作,只能通过手动完成;当为0时,表示不开启自动操作,当为非0时,表示按照指定的时间周期dump操作,重启后自动完成restore的操作。

P.S.: 该特性的选项innodb_auto_lru_dump是在XtraDB的5.5.10-12.1版本中被引入,到5.5.10-20.1起将其重名为innodb_buffer_pool_restore_at_startup。

手动操作如下:

mysql> show status like ‘innodb_buffer_pool_pages_data’;    — 查看重启前后当前page页的个数

mysql> select * from information_schema.XTARDB_ADMIN_COMMAND /*!XTRA_LRU_DUMP*/;   — 备份innodb_buffer_pool

mysql> select * from information_schema.XTARDB_ADMIN_COMMAND /*!XTRA_LRU_RESTORE*/;   — 恢复innodb_buffer_pool

P.S.: 以上手动备份恢复的操作语句还没有加入到XtraDB的任何版本中,只是在Percona的test环境中实现了。

- TAKEAWAYS -

Innodb Buffer Pool是InnoDB性能提升的核心,它既可以缓存数据还可以缓存索引。缓存的数据部分是数据块构成的page页,而不像Query Cache仅存的SQL对应的结果集。Buffer Pool上可以完成数据的更新变化,减少随机i/o的操作,提高写入性能,而Query Cache最忌讳表的数据更新,会导致相应的cache失效,带来额外系统消耗。之前听过这么一句很精辟的对于buffer与cache的总结:buffer是用来加速写,cache是用来缓冲读。在实际中,尽可能的增大innodb_buffer_pool_size的大小,把频繁访问的数据都放到内存中来,尽可能减少Innodb对于磁盘i/o的访问,把InnoDB最大话成为一个内存型引擎。

innodb_buffer_pool_size的大小,当系统启动后,会比之前指定的要多出大小的10%,避免过大导致OS发生swap动作,留出足够的给OS使用;show engine innodb status\G命令输出中BUFFER POOL AND MEMORY部分有关于buffer pool使用情况的提示,可以关注这么三项:Free buffers表示未被使用的,经过一段时间后,仍然保持不少的空闲buffer,说明该参数设置过大,如果为0,说明该参数设置的大小不能满足需求;Database pages表示目前有多少数据页已经被缓存到buffer pool中;flush list表示dirty pages的数量,有多少跟新的页没有被刷回磁盘,当缓存的列表太大时,会使正常关闭mysqld变得很慢,也会使意外发生后Crash Recovery的动作只持续相当长时间(会是你无法忍受的);Buffer pool hit rate表示buffer pool的使用效率。

    猜你喜欢
    发表评论
    喜欢该文的人也喜欢 更多