互联网应用的一个特点就是大量的使用缓存技术。目前已知的缓存技术非常多,比如memcache、guava cache等等,当然这些都是比较上层的技术,而Linux系统底层的缓存,仍然是依赖于一些经典的页面置换算法来实现,这里着重介绍几个重点的算法。
- LRU(Least Recently Used)
顾名思义,最近最少使用算法,这个算法的理念是:如果数据最近被访问过,那么它将来被访问的几率也很高。
算法的实现有很多种,基本都是通过数据的历史访问记录来作文章。但这个算法有一个比较明显的问题,就是在某些波动的情况或者周期性的批量数据访问下,缓存的命中率会大幅下降,也就是判断某一时刻的热数据而将广域的热数据剔除掉了。
目前这个算法有很多变种,比如LRU-K(k就是最近使用过的次数),它将LRU的最近使用一次扩展成了最近使用K次(本质上是LRU与LFU的结合),进过验证k=2的时候,效率可以达到一个比较均衡的高水平。
- LFU(Least Frequently Used)
最近最少频率,每个数据块维护一个访问计数,一定时间内,按照这个计数的大小,选择计数值最小的页面进行淘汰
- FIFO(First-In First-Out)
最简单的先进先出淘汰方式,选择最先进入缓存的页面进行淘汰
- MQ(Mutil Queue)
MQ实际上是LRU的一种扩展,希望做到的是尽量的贴近实际用户最可能访问的逻辑,将访问的热点数据缓存起来。
MQ算法根据访问频率将数据划分为多个队列,不同的队列具有不同的访问优先级,其核心思想是:优先缓存访问次数多的数据。
MQ算法将缓存划分为多个LRU队列,每个队列对应不同的访问优先级。访问优先级是根据访问次数计算出来的
详细的算法结构图如下,Q0,Q1….Qk代表不同的优先级队列,Q-history代表从缓存中淘汰数据,但记录了数据的索引和引用次数的队列:
通过对几个队列的维护,保证:
新的被多次访问的数据优先级可以提升
旧的访问次数减少的数据优先级被降低
具体的做法就是在多个不同优先级序列的队列之间切换。当然这个算法相对于LRU来说复杂了许多,并且在大量数据涌入的时候可能会造成一些由于系统本身置换而产生的效率影响。
除了MQ,还有2Q(Two Queue)等等,都是对LRU经典算法的改进,不过由于本身算法复杂度和空间占比的影响,使用率都不高。