1 LRU算法
1.1 前言
目前尽量由于摩尔定律,但是在存储硬件始终存在着矛盾,例如在容量方面,内存<外存;而在硬件成本与访问效率方面,内存>外存,并且这种区别是不在同一数量级别的差异。而目前互联网服务平台存在的特点:读多写少,数据规模巨大,长尾效应等等。正是由于场景需求与存储硬件之间的本身矛盾,缓存算法由此产生了。
一个服务平台其读取过程:总是优先去离CPU最近的地方内存中读取数据,当有限的空间读取命中为空时,则去外存的数据库或文件系统中读取。当有限的缓存空间里“人满为患”时,而又有新的成员需要加入时,自然需要一定的淘汰机制。本能的基础淘汰算法,最后访问时间最久的成员最先会被淘汰(LRU),而队列访问具有先进先出的特点,按最后访问的时间先进先出,所以通常用队列实现LRU。
1.2 基本原理
a 利用队列类型对象,记录最近操作的元素,总是放在队首,这样最久未操作的元素自然被相对移动到队尾;同时,当元素总数达到上限值时,优先移除与淘汰队尾元素。
b 利用HashMap辅助对象,快速检索队列中存在的元素。
1.3 操作
a 写入操作: 新建一个元素,把元素插入队列首,当元素总和达到上限值时,同时删除队尾元素。
b 读取操作:利用map快速检索,队列相关联的元素。
1.4 实现源码
a 自定义链表方式
b 利用stl::list类型实现方式
2 LRFU缓存算法
2.1 前言
缓存算法有许多种,各种缓存算法的核心区别在于它们的淘汰机制。淘汰机制的通常做法:所有元素按某种量化的重要程度进行排序,分值最低者则会被淘汰。而重要程度的量化指标又通常可以参考了两个维度:1. 最后被访问的时间 2. 最近被访问的频率次数。例如如下:
LRU(Least Recently Used ),总是淘汰最后访问时间最久的元素。这种算法存在问题:可能由于一次批量冷数据的查询而误淘汰大量热点的数据。
LFU(Least Frequently Used ),总是淘汰最近访问频率最小的元素。这种算法也存在明显的问题:
a 如果频率时间度量是1小时,则平均每个小时内的访问频率1000的热点数据可能会某段时间的随机访问频率是1001的数据剔除掉;b 最近新加入的数据总会易于被剔除掉,由于其开始的频率低。本质上重要性访问频率是指在多长的时间段内的频率?其难以标定,在业界很少单一直接使用。由于两种算法的各自特点及缺点,所以通常在生产线上会根据业务场景联合LRU与LFU一起使用,称之为LRFU。
2.2 实现机制
我们在LRU实现基础上稍作衍生,能实现LRFU缓存机制,即可以采用队列分级的思想,例如oracle利用两个队列维护访问的数据元素,按被访问的频率的维度把元素分别搁在热端与冷端队列;而在同一个队列内,最后访问时间越久的元素会越被排在队列尾。
参考:
a https://en.wikipedia.org/wiki/Least_frequently_used
b
c