参考:
https://www.cnblogs.com/changbosha/p/5849982.html
https://blog.csdn.net/weixin_42463676/article/details/80843711
名词解释
- 过期策略:即redis针对过期的key使用的清除策略,策略为,定期删除+惰性删除
- 内存淘汰机制:即内存占用达到内存限制设定值时触发的redis的淘汰策略来删除键
过期策略
定期删除:redis默认每隔100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每隔100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。
惰性删除:也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。
在实际使用中,由于redis的惰性删除策略踩过一个坑,问题步骤如下:
- get 某个 过期的key,此时惰性删除触发,该key被删除
- 判断这个key的value是否有值
- 有值则执行一段lua脚本,lua里面再次获取了该key,但是发现该key已经不存在了
所以,惰性删除策略的存在,不能简单的以该key有value,来断定这个key尚未过期。而是需要用TTL
判断一个key是否过期。
过期策略存在的问题,由于redis定期删除是随机抽取检查,不可能扫描清除掉所有过期的key并删除,然后一些key由于未被请求,惰性删除也未触发。这样redis的内存占用会越来越高。此时就需要内存淘汰机制。
内存淘汰机制
redis配置文件中可以使用maxmemory <bytes>将内存使用限制设置为指定的字节数。当达到内存限制时,Redis会根据选择的淘汰策略来删除键。(ps:没搞明白为什么不是百分比)
策略有如下几种:(LRU的意思是:Least Recently Used最近最少使用的,LFU的意思是:Least Frequently Used最不常用的)
volatile-lru:在带有过期时间的键中选择最近最少使用的。(推荐)
allkeys-lru : 在所有的键中选择最近最少使用的。(不区分是否携带过期时间)(一般推荐)
volatile-lfu :在带有过期时间的键中选择最不常用的。
allkeys-lfu : 在所有的键中选择最不常用的。(不区分是否携带过期时间)
volatile-random :在带有过期时间的键中随机选择。
allkeys-random :在所有的键中随机选择。
volatile-ttl: 在带有过期时间的键中选择过期时间最小的。
noeviction:不要删除任何东西,只是在写操作上返回一个错误。默认。
这里补充一下主键空间和设置了过期时间的键空间,举个例子,假设我们有一批键存储在Redis中,则有那么一个哈希表用于存储这批键及其值,如果这批键中有一部分设置了过期时间,那么这批键还会被存储到另外一个哈希表中,这个哈希表中的值对应的是键被设置的过期时间。设置了过期时间的键空间为主键空间的子集。
同时Redis也支持Runtime修改淘汰策略,这使得我们不需要重启Redis实例而实时的调整内存淘汰策略。
内存淘汰的过程
我们可以通过配置redis.conf中的maxmemory这个值来开启内存淘汰功能,至于这个值有什么意义,我们可以通过了解内存淘汰的过程来理解它的意义:
- 客户端发起了需要申请更多内存的命令(如set)。
- Redis检查内存使用情况,如果已使用的内存大于maxmemory则开始根据用户配置的不同淘汰策略来淘汰内存(key),从而换取一定的内存。
- 如果上面都没问题,则这个命令执行成功。
maxmemory为0的时候表示我们对Redis的内存使用没有限制。
几种淘汰策略的适用场景
allkeys-lru:如果我们的应用对缓存的访问符合幂律分布(也就是存在相对热点数据),或者我们不太清楚我们应用的缓存访问分布状况,我们可以选择allkeys-lru策略。
allkeys-random:如果我们的应用对于缓存key的访问概率相等,则可以使用这个策略。
volatile-ttl:这种策略使得我们可以向Redis提示哪些key更适合被eviction。
另外,volatile-lru策略和volatile-random策略适合我们将一个Redis实例既应用于缓存和又应用于持久化存储的时候,然而我们也可以通过使用两个Redis实例来达到相同的效果,值得一提的是将key设置过期时间实际上会消耗更多的内存,因此我们建议使用allkeys-lru策略从而更有效率的使用内存。