研究H2的过程中发现新的存储引擎MVStore使用了新的cache替换算法——LIRS,经过一系列相关的论文研读,发现比旧存储引擎PageStore的LRU算法改良不少。为了更好地了解LIRS的优异性,把同样属于LRU变种的基于倒数第二次访问时间对比进行cache替换的LRU-K(K一般为2)[1],2Q[2],LIRS[3]算法进行对比。
为方便讨论,统一称呼要进行缓存的对象为块(或Page)。在访问块的行为中,假定存在时间局部性原理,(temporal locality - locations referenced recently likely to be referenced again)。cache替换算法就是针对局部性原理,分辨哪些是访问频率高的hot块,哪些是访问频率低的cold块,并缓存hot块到cache中,从而提高cache命中率。但对于现实中的数据存在不同的访问规律,因此cache算法为了必须尽快地适应块访问规律的改变,缓存新的hot块,并同时避免cold块“污染”hot块的缓存。
论文[3]提出了4种块访问规律:
1.顺序访问。所有的块一个接一个被访问,不存在重访问。
2.循环访问。所有块都按照一定的间隔重复访问
3.时间密集访问。最近被访问的块是将来最有可能被访问的。
4.概率访问。所有块都有固定的访问概率,所有块都互相独立地根据概率被访问。
论文[1]提出了2个访问规律中出现的问题:
5.Correlated References。关联访问,即块被首次访问之后,紧接着的短时间内会有数次访问。
6.Reference Retained Information Problem。访问信息保存问题。即需要在块替换出cache后,仍然保留之前的访问信息。
由于传统的LRU算法存在较多的问题,如顺序块访问会把hot块替换出cache,对于索引块和数据块的循环访问时,不会根据访问概率缓存索引块。LRU-K,2Q,LIRS等cache替换算法就是为了解决LRU算法的问题,提供同样甚至更高性能的同时,同时不需要外部的调控,能够自动根据块访问规律的改变对cache进行调整,都是作为通用的块缓存算法。
K指的是最后第K次访问的距离,也就是倒数第K次访问时和最近一次访问的时间差。LRU-K算法主要是对比最后第K次的访问距离,访问距离越大则代表每次的访问间隔越长,因此更容易被替换出cahce。另外论文[1]中提出了对于稳定不变的访问规律,K越大,cache命中率会越高,但对于访问规律变化较大的时候,K越大则表明需要更加多的访问去适应新的规律,因此变化响应更差,因此一般取K=2。
原论文考虑到访问规律出现5,6中的问题,提出了Correlated References Period和Reference Retained Information Period两个时间间隔参数。
Correlated References Period,指块首次访问后的一段时间。块(可能是cold或者hot)的首次访问后可能会接着数次短时间内的关联访问,如数据库中同一事务内的select和update会多次扫描相同的块,为了避免关联访问的干扰造成对块的错误判断,在第一次访问块后,会预留在cahce中。在这段时间内的多次访问只算作一次访问。只有这段时间后块再次被访问,才算第二次被访问。
Reference Retained Information Period,则指块被替换出cache后的一段时间。块被替换出cache后,可能很快地再次被访问,由于之前访问记录已丢弃,这样只算作首次访问,之后又很快被替换出cahce后,又再次被访问,这样又只会算作首次访问,如此下来,虽然块被频繁访问,属于hot块,但由于替换出cahce后没有保留访问信息,导致错误判断。因此对于替换出cache后的块会继续保留访问信息一段时间。
由于原论文只给出伪代码,并没有具体的实现。虽然网络上有各种的LRU-K的实现,但某些如多个LRU栈组合的实现并不符合论文的思路。因此结合以上的讨论,个人总结了一个改进后的简单实现(K=2):
总结
以上实现中,总共有3个队列,A1,A2,P。其中cache分配给在A1和P和的块,P所占cache比例较大。A2只保存块的访问信息。块的访问信息包含倒数第二次访问时间,最后一次访问时间等。如果扩展到K,则只需要通过保存K次的访问时间,同时初始化为0即可。
LRU-K对于LRU的改进,最主要是采用了更为激进的方法去替换cold块出cache,这样能够较好地避免顺序访问对cache的影响以及能够更好地区分块访问的频率,但同时,LRU-K算法中存在一些问题:
1.由于优先级队列的排序操作需要额外的O(logN)的时间复杂度,N为P的大小。
2.A1,P和A2的大小都必须按照实际情况进行配置取最优比例,才能发挥最优性能。
3.块的访问频率变化响应较慢。这是因为P的比较是按照历史的最后第K次访问距离进行比较。如果块A在P中的时候倒数第K次的距离较少,但经过较长时间才有新的访问,重新更新访问距离后,才会被快速替换出cache。
2Q指的是Two Queue,就是依靠两个队列实现的cache替换算法。针对LRU-K算法的O(logN)时间复杂度,2Q目的是实现O(1)时间复杂度,不需要设置额外参数,并且性能等同甚至优于后者的通用cache替换算法。另外2Q算法也同样解决了LRU算法中的限制,即顺序访问,以及索引块和数据块循环访问的问题。
论文[2]中首先提出了简化的实现方法:
总结
可以看到,和LRU-K比较最后K次访问距离,快速替换出cache中cold块相比,2Q通过对比Am的最近访问时间,替换块出cache,目的是使hot块能常驻在cache中。另外要注意到A1in和A1out两个队列的作用,A1in主要是作为Correlated References Period的实现,而A1out则是需要分辨hot块和cold块,在测试中发现A1in的块适合分配cache,A1out的块则更适合分配块指针。2Q对比LRU-K,只需要记录更少的信息,更少参数配置(推荐Kin为25%,Kout为50%),以及更低的时间复杂度O(1)。3.Belady’s anomaly:cache大小增加反而导致cache命中率下降[3]。
LIRS,Low Inter-reference Recency Set,主要通过比较IRR(Inter-Reference Recency )来决定哪些块被替换出cache。LIRS也是目标实现一个低开销,不需要额外参数设置,并且性能优异于其它同类型的cache替换算法。
首先要了解一下LIRS的两个概念:
recency,最近被访问的时间。
Inter-Reference Recency (IRR),同一块连续两次访问期间中间访问过的不重复块数。IRR用于记录块的历史信息,假定IRR值大的块,其值接下来也会大,也就是访问频率低。因此选择IRR大的块进行replacement,但要注意这些块的recency可能会比较低,也就是可能是最近才被访问的块。
LIRS算法动态区分低IRR(LIR)和高IRR(HIR)的块,LIR块一般会常驻cache,HIR块则会较快被替换出cache。要保证所有LIR块都能缓存,只有比例较小的cache供HIR块缓存,当LIR块的recency超过某个值,HIR块在一个更小的recency中被访问,两者的状态就会交换。
论文给出了详细的实现:
Stack S: 包括LIR块、少于LIR块最大recency的HIR块(包括已经缓存或者没有缓存)
Queue Q: HIR块缓存队列,FIFO
3.对于IRR变化不会太敏感。如某些cold块IRR瞬间变小,变成LIR块,这样会把栈S底部的LIR块变为HIR块,从而很快被替换出cache,这样就造成后面的cache miss
LRU-K,2Q,LIRS三种算法都基于倒数第二次的访问时间,以此推断块的访问频率,从而替换出访问频率低的块。从空间额外消耗来看,除了LRU-K需要记录访问时间外,LIRS需要记录块状态(HIR/LIR等),2Q并不需要太多的访问信息记录,因此2Q>LIRS>LRU-K。从时间复杂度来看,LRU-K是O(logN),2Q和LIRS都是O(1),但LIRS的"栈裁剪"是平均的O(1),因此2Q>LIRS>LRU-K。从实现复杂来看,LIRS只需要两个队列,2Q和LRU-K的完整实现都需要3个队列,因此LIRS>2Q=LRU-K。最后,LIRS是唯一参数不需要去按照实际情况进行调整(尽管仍然有LIR和HIR的cache大小参数),2Q和LRU-K都需要进行细微的参数调整,因此LIRS>2Q=LRU-K。从性能角度来看,LIRS论文看得出还是有一定的提升,LIRS>2Q>LRU-K。
本文目前只比较了三种LRU变种算法,事实上,还有基于业务情况,基于访问模式探测等不同类型的cache替换算法。另外对于LRU变种算法中,ARC也是值得探索的。我们应该明白并不存在万能的cache替换算法可以适用于任何情况。事实上,在真实database应用中,一般会对论文中的算法做适当的调整和扩展,使其更适用自身,能够发挥最佳性能。
[2]T. Johnson and D. Shasha, “2Q: A Low Overhead High Performance Buffer Management Replacement Algorithm”
[3]Song Jiang and Xiaodong Zhang, "LIRS: An Efficient Low Inter-reference Recency Set Replacement Policy to Improve Buffer Cache Performance"