1.Redis过期删除
在使用redis存储数据时,我们一般会对数据设置过期时间,使得这些缓存在过期之后能被清除,释放珍贵的缓存资源。那过期清理是用什么策略来实现的呢?
redis主要通过以下两种方式
1.1 定期删除
1.redis每过100ms,从设置了过期时间的key中随机取出20个缓存key
2.清除其中的过期key
3.若过期key占比超过1/4,则重复步骤1
为什么定期删除采用的是随机策略,而不是对全部数据做清理
呢?因为每100ms过滤所有缓存数据,对CPU压力较大。
虽然定期删除
解决了一部分过期数据的问题,但是还有不少数据并没有被清除出缓存,所以此时就有了惰性删除
1.2 惰性删除
某个缓存key在查询时,若此时已过期,则会从缓存中删除,同时返回空
这种方式是被动触发的,
定期删除
与惰性删除
虽然能清理一部分过期数据,但还存在一个问题:
部分过期缓存key未被清理出缓存,长久占用缓存资源(随机策略存在的缺陷性),随着缓存数据的不断增加,
无法通过删除过期key的方式腾出空间,来储存新的热点数据。
这种情况下,如何淘汰旧的缓存数据,储存新的热点数据呢?内存淘汰机制
2.内存淘汰机制
redis提供8种策略来应对当使用内存达到限制值的情况
1.noeviction: 返回错误,不删除任何键值
2.allkeys-lru:尝试回收最少使用的键值(LRU算法)
3.volatile-lru:尝试回收最少使用的键值,但仅限于在过期键值集合中
4.allkeys-random:回收随机的键值
5.volatile-random:回收随机的键值,但仅限于在过期键值集合中
6.volatile-ttl:回收过期集合的键值,并优先回收存活时间较短的键值
7.allkeys-lfu:回收最少使用频次的键值(LFU算法)
8.volatile-lfu:回收最少使用频次的键值(LFU算法),但仅限于在过期键值集合中
这里有两个重要的算法:
LRU:最近最少被使用。访问时间越早越容易被淘汰
LFU:最近最少使用频次。使用频次越少越容易被淘汰
Redis的LRU算法采用一种近似LRU的方式来实现,通过对少量keys(maxmemory-samples,默认为5)进行取样,然后回收其中一个最好的key(被访问时间最早的)。
Redis3.0算法已改进为回收键的候选池子
1.第一次随机选取的key都放入一个pool中(pool大小为16),pool中的key是按照访问时间大小排序;
2.接下来每次随机选取的key都必须小于pool中最小的key,若pool未填满,则重复步骤1
3.放满之后,每次有新的key需要进入时,需要将pool中lru最大的一个key取出
4.淘汰的时候,直接从pool中取出一个lru最小的一个key然后淘汰
Redis有了LRU
之后,为什么还需要LFU
呢?因为Redis作者发现就算提高采样数量或者pool的大小,也无法再提高缓存命中率,而LFU算法能起到更好的效果。
LFU近似于LRU,它使用一个概率计数器(morris counter),用来估计访问频率;counter的计数有两个特点,1.随着访问次数的增加,counter的计数会越来越缓慢(counter最大值为255),2.随着时间的流逝,counter会逐渐衰减。淘汰时也会有一个pool,也采取与LRU类似的方式,但是排序是按照计数从大到小排列(越靠后越容易被淘汰)
为什么Redis不采用标准LRU算法:
标准LRU算法为了达到查找和删除的时间复杂度一般采用hash表
和双向链表
结合的数据结构。这样会增加额外的内存占用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。