参考资料
算法描述
2Q: two queue(s) algorithm
应用最广泛的缓存替换算法应该是LRU了,其实现简单有效。但正是因为其简单,对于某些访问场景来说表现并不出色。LRU用新访问页替换冷页,但新换入的页在之后可能再也不会访问到,不仅如此它还会在内存中停留很长时间才会淘汰出去。之后LRU-K算法被提出,跟踪倒数第K次内存页引用的时间,以确保冷页能够尽快淘汰出去。
在O'Neil-Weikum 的论文提出了LRU/2算法,即K=2情况下的LRU-K,相对于LRU的提升在于采用了更加积极一些的置换策略,从而将冷页换出,换出的操作涉及到优先队列的操作。 相对于其他缓存替换算法来说,LRU/2 虽然是自适应的,但还是有两个参数需要关注优化。首先是 Correlated Reference Period(关联引用间隔),即缓存在被访问后在内存中停留的时间。在LRU/2中 同一进程连续的访问(correlated accesses)可以在buffer中获得该页,但如果是多个进程连续访问这一page的情况,该页并不会获得更高的优先级。 第二个参数 Retained Information Period,指在缓存被淘汰后其访问记录还会被保留多久。作者建议设置为200秒,但更高的值也不会有太坏的影响。
2Q与LRU/2对于LRU的改进在某种程度上存在互补性,2Q并不是通过直接将冷页从主缓存中剔出,而是通过将热页换入的形式来实现。与LRU/2算法类似,2Q以该页的第二次被访问时间来计算。简单来说,在某一页第一次被访问的时候,2Q将其放入一个特殊的缓冲区,称为A1 queue,其实现就是一个FIFO队列,如果该页在A1 queue的生存周期内被再次访问,则可能是热页,将其置入Am queue,其实就是一个LRU。如果在A1 queue的生存期内没有再次被访问到,则将其换出。
实现
if p is on the Am queue then put p on the front of Am queue /* Am is managed as an LRU queue */ else if p is on the A1 queue then remove p from the A1 queue put p on the front of Am queue else /* first access we know about concerning p */ /* find a free page slot for p */ if there are free page slots available then put p in a free page slot else if A1's size is above a (tunable) threshold delete from the tail of A1 put p in the freed page slot else delete from the tail of Am put p in the freed page slot endif put p on the front of the A1 queue endif
测试后发现这种解决方案对于平 均分布的访问请求表现良好,但在实际应用场景中性能不佳。在现实应用中, 访问的区域性变化很大,例如有些页会在短时间内频繁访问,之后很长时间没 有访问了。改进后的2Q将 A1 队列分成 A1in 和 A1out。第一 次访问会进入 A1in,但之后直接进入 A1out,在 A1out 中被引用的页则进入 Am。
// if there is space, we give it to X // if there is no space, we free a page slot to // make room for page X reclaimfor(page X) begin if there are free page slots then put X into a page slot else if(|A1in| > Kin) page out the tail of A1in; call it Y add identifier of Y to the head of A1out if (|A1out| > Kout) remove identifer of Z from the tail of A1out endif put X into the reclaimed page slot else page out the tail of Am, call it Y // do not put it A1out; it hasn't been // accessed for a while put X into the reclaimed page slot endif end On accessing a page X: begin if X is in Am then move X to the head of Am else if (X is in A1out) then reclaimfor(X) //这块感觉有点问题,X的空间应该已经在进入A1in的时候准备好了? add X to the head of Am else if (X is in A1in) // do nothing else //Xisinnoqueue reclaimfor(X) add X to he head of A1in endif end
理论基础
在 2Q 算法中,A1 队列作为过滤器存在,数据只有在进入 A1out 队列后再 次被访问才能进入 Am 队列。假设 miss(与 A0 算法比较后认为是判断失误的部 分) 的几率是 m,且 A1out 队列空间为 f。因为 A1out 队列经常是满的 (miss 率远大于 A1out 的命中率),因此忽略命中的情况下对A1out的影响。这样一来,数据在进入 A1out 队列后经过 f/m 次的访问如果被访问到则会进入 Am 队列,我们将这个概率称作 paccept 。 假设对象 i 被访问的几率是 pi,该对象在第 k 次访问后由 A1out 进入 Am 队 列的几率是 pi(1−pi)k−1 ,由此得出:
paccept 的概率随着pi的增大而趋近于1,随着 pi 的减小而趋近与零,因此A1out起到了过滤冷页的作用。我们可以将A1out 过滤器的cutoff hotness定义为访问概率, pcutoff , 在 paccept=1/2 的情况下, paccept 的derivative很大, 被访问概率为 pcutoff 的对象在经过三次而不是两次访问后将被换入Am队列。因此,对于以下方程:
得出其概率。在f和m已知的情况下,我们可以推算出 paccept 的概率为50%的对象的访问率,
(估算是通过泰勒级数展开,在 m/f≤0.1 的情况下误差小于4%)
从上式中可以看到A1out过滤器能够自调整,当miss率高的时候, pcuttoff 也会相对较高,因此只会将最热的那些对象换入,miss率低时则中度热对象则有足够的几率换入。
接下来,假设p_i和m已知,可以得到在 paccept 的条件下的 f=fcrit :
估算成立的条件是是 ln(1−pi)≈−pi .如果已知Am队列中的访问频率下限,就可以得出f,但是在这里无法预先得知访问概率(否则就直接使用A0算法了)。为了粗略的估算,让我们找出 f=fapprox 的值,可以有%50的概率将平均热度的对象放入Am队列,如果miss率是m且Am的size是B,buffer中一个对象的平均访问概率是 (1−m)/B ,用 fcrit 替换 f ,我们可以得到
由于以上公式要求预估miss率,实际意义有限。但是它说明了A1out的size与buffer size的比例应该是固定的B。模拟实验表明在m的值在10%到90%之间时,这个比例应该是1/2,对于m更小的系统A1out队列的size也应该更小。
Am的size一般是数据全集的一小部分,设D为数据全集,并且 B=rD ,得出
冷数据的平均访问几率是 m/(1−r)D 。假设 X=m/D ,我们可以得出冷数据的平均访问几率是 11−rX ,因此:
因为r很小, 2ln(2)r≫11−r ,在 f=B/2 的情况下只要 r 足够小便可以过滤掉冷数据。不仅如此 fapprox/B=1/2 得出 m=1/(1+2ln(2))≈0.419 。只要m不大, fapprox 的值波动不会很大(如果m很大那也没什么办法了),可以得出该算法的性能对于 f 的设置并不敏感, f=B/2 的设置基本上总是不错的。
PS:文中所述的A0算法应该指 Belady's Algorithm