之前聊过了WEB服务器缓存的使用场景,当时是基于缓存常见的问题聊的,当然在实现缓存功能和解决缓存问题的时候,也是需要用到算法的,那么这次我们聊聊基于缓存常见的算法。
缓存污染
还是先聊聊缓存的问题,除了之前聊的雪崩,击穿,穿透之外,缓存还有一些常见的问题,比如缓存污染,就是将一条不是很常用的数据缓存到缓存里(这句话好别扭),导致缓存资源被浪费(尤其是以内存作为缓存,内存缓存可以提供的存储大小本来有限),所以必须要有些策略来解决这个问题,也就是这次想聊的算法。
FIFO算法
这个名字起初听说的时候,觉得相当高级,但是看到他的英文全程就觉得一般了,first in first out,先进先出,啥意思,这里在缓存内容的时候,如果缓存已经满了,那么最先存入缓存的内容将要被舍弃。类似堆的数据结构,在好多语言里有实现的功能模块,比如Python内容的Queue模块就有先进先出队列:
import queue
q = queue.Queue(5) #构建一个长度为5的先进先出的队列
q.put(1)
q.put(2)
print(q.get()) # 返回1
LRU算法
LRU是Least Recently Used的缩写,翻译成中文就是最近最少使用,算法的逻辑是,在缓存当中,如果一个数据被访问,那么就会把它置顶,这样类似冒泡算法,存放在缓存尾部的就是最少被用到的那个缓存数据,假如缓存已经满了,再次缓存就会先清掉尾部不常用的缓存数据。
LFU算法
这里要注意的是LRU只是在一定程度上避免了缓存污染,如果忽然有大量的非热点数据进入缓存,还是会出现污染,所以还需要其他的算法,那么LFU就被LRU要好很多,LFU是在缓存数据队列的基础上,创建一个映射来记录每个缓存使用的次数,当缓存满了之后,将访问次数最少的缓存清除掉。
TinyLFU算法
TinyLFU算法还是基于LFU算法的升级,因为LFU算法尽管比LRU要好很多,但是给每个缓存计数对空间的损耗也是很大的,所以TinyLFU算法从降低LFU算法维护计数器的成本出发来设计,基本的防止缓存策略是一致的,但是对每个缓存的计数器通过位图来记录,这个类似之前聊过的布隆过滤器的方式。
仔细聊的话,TinyLFU的核心采用了count-min sketch算法,这个算法的逻辑类似之前聊过的布隆过滤器的方式(这里的图是不是很熟悉):
W-TinyLFU算法
TinyLFU算法已经降低了计时器的成本,但是基于秒杀类型的,突然访问类暴增,后续没有访问量的缓存也是没有办法的,所以在TinyLFU算法的基础上加上了衰减逻辑,就是每当过了一个时间或者是缓存引用计数到达设置的最大域指,这个时候,让计数衰减,比如折半。这样偶发性的大计数问题也就被解决了。
关于解决缓存污染的算法就聊这么多,没有做代码实现,还请各位大佬多多指点。