MySQL提供了一个比较有用的功能,能够把buffer pool LRU上的block对应的page id 和space id 存储到文件中。在重启时,会自动读取这个转储文件,然后把对应的<space id, page id>读入到buffer pool中,快速预热内存,以尽快提供服务。
参数
使用该特性比较简单,通过多个参数控制. 简单说下几个参数
转储到文件:
innodb_buffer_pool_dump_now : 立刻做一次buffer pool LRU dump
innodb_buffer_pool_dump_at_shutdown : 在正常关闭实例时做一次转储
从文件中恢复:
innodb_buffer_pool_load_at_startup : 在启动实例时读入转储文件中记录的Page
innodb_buffer_pool_load_now : 立即做一次转储文件读入
innodb_buffer_pool_load_abort:立刻中断LOAD操作
5.7新加参数(http://dev.mysql.com/worklog/task/?id=6504)
innodb_buffer_pool_dump_pct : 表示转储每个bp instance LRU上最热的page的百分比。通过设置该参数可以减少转储的page数。
实现原理:
这部分代码的实现比较简单,就是在开始实例时起一个单独的线程,做page导入工作。
入口函数为buf_dump_thread, 该线程同时负责dump 和load
LOAD:
调用函数buf_load,打开转储文件,从其中读取<space_id, page_id>,并合并成一个unsigned long long类型(BUF_DUMP_CREATE),高32位为space id , 低32位为page id。这主要是为了随后对其进行快速排序(std::sort),这样就可以最可能的顺序读磁盘文件。 这对机械硬盘是有利的。但如果我们使用的是类似SSD盘,并且随时可能abort掉load操作时,我们当然希望是按照从转储文件的记录顺序读入,因为文件头总是记录的最“热”的Page (TODO)
如果转储文件中的page数大于当前Buffer pool能够容纳的page数,则忽略多出来的page。
读取page接口函数buf_read_page_background
buf_load_throttle_if_needed: 每load innodb_io_capacity 个page,会检查innodb是否active(有用户负载),以及距离上次检查的时间间隔是否超过了1s,如果没有超过,则sleep一段时间,目的是保证1秒内读入的page数不超过innodb_io_capacity
DUMP:
dump的入口函数是buf_dump,遍历每个bp instance,根据参数innodb_buffer_pool_dump_pct计算需要记录的page数, dump的过程中持有buffer pool instance 的mutex.
目前存在的问题(5.6,5.7)
目前BP LOAD是以同步读入page的方式载入buffer pool,因此效率比较低,在我的测试机器上,只有60M/s左右的读入速度。如果修改成异步载入,可以达到每秒400M。
具体可以参考http://bugs.mysql.com/bug.php?id=73583
5.7相关代码:
http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6230