InnoDB的缓存替换策略及其效果

我们开发自己的存储引擎页面缓存替换策略的过程中主要是参考了InnoDB与LRU-K算法。InnoDB缓存替换策略使用分代与LRU相结合的方式。分为old和young两个分代,系统维护old分代占总buffer大小的3/8左右。当一个页面第一次被访问时,是加入到old分代的lru头。并不是每次访问一个页面时就将这个页提到lru的头部,而是在这个页面在LRU中的位置调整后,是否有很多页面已经被替换出去,若有,则将这个页面移到LRU头。系统在每个页记录调整该页在lru中位置当前系统总共替换了多少个数据页,比较页中记录的这个计数与系统全局页替换计数,就可以发现上次调整这个页在lru链表中位置后,系统中又有多少个页被替换,若比较多,则再次调整该页在lru中的位置。由于第一次访问的页被加入到old分代中,因此一次表扫描不会导致young分代中的页被替换出去。

总的来说InnoDB的缓存替换策略非常简单,性能开销很低,但不知道其效果如何,因此今天进行了测试。测试时的表每条记录包含一个INT和两个CHAR(200)类型的字段,共20万条记录,其访问概率使用screw为1.2的Zip-f分布生成,这样访问概率最高的10%的记录的总访问概率为95%。表大小约占7000个页面,测试时设置InnoDB可用于存储数据的缓存页为730(InnoDB缓存大小必须设置为64个页的整数倍,无法精确控制到700个),约为数据量的10%。这时,理论上最优的缓存失配率应为5%。

使用10个线程进行测试,每个进行100000次随机操作,每个操作根据概率随机访问一条记录。测试之前先进行了一次全表扫描来预热。

测试之前各类读操作统计如下

| Innodb_buffer_pool_reads          | 77        |
| Innodb_data_reads                 | 7004      |
| Innodb_pages_read                 | 6994      |

测试之后各类读操作统计如下

| Innodb_buffer_pool_reads          | 72055      |
| Innodb_data_reads                 | 95197      |
| Innodb_pages_read                 | 95187      |

如果按Innodb_buffer_pool_reads计算,即不考虑预读时,测试期间读取的页面数为72000左右,失配率为7.2%。如果按Innodb_pages_read计算,即考虑预读时,测试期间读取的页面数为88200左右,失配率为8.8%。如理想的5%相比两者都还是有一定距离的。若能优化到理想状态,大致可以减少40%的IO。

同样的条件对比测试了一下,我们的存储引擎测试期间产生的读操作为62100次,稳定时的失配率为6.1%左右。目前还不清楚为什么我们的存储引擎为什么表现会比InnoDB要好,因为两者的策略是类似的。可能是因为InnoDB中的预读机制在这类纯随机的负载下反而会影响到缓存的命中率。由于Innodb_pages_read明显的超过Innodb_buffer_pool_reads的增长,可以看出测试过程中InnoDB也在不定的进行预读,有可能预读进来无用的页面,导致有用的页面被替换出去。我们的存储引擎的预读检测机制有所不用,在测试期间没有发生预读。

觉得文章有用?立即: 和朋友一起 共学习 共进步!

猜您喜欢

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>