Redis是基于内存操作的非关系型数据库,Redis中提供了多种内存回收策略,当内存容量不足时,为了保证程序的运行,这时就不得不淘汰内存中的一些对象,释放这些对象占用的空间,那么选择淘汰哪些对象呢?

Redis的内存回收,主要围绕如下两个方面来进行:

      ①Redis过期策略:删除已经过期的数据;

      ②Redis淘汰策略:内存使用到达maxmemory上限时触发内存淘汰数据。

      Redis的过期策略和淘汰策略是两个不同的概念,接下来将分开讲解这两种策略

1.Redis过期策略

       在Redis中,提供了expire命令设置一个键的过期时间,到期之后Redis会自动删除它,这个在我们的实际使用过程中用的非常多,Redis中设置过期时间有如下两种方式:

      ①expire命令:expire key seconds(先set key,然后设置过期时间。其中seconds 参数表示键的过期时间,单位为秒。expire 返回值为1表示设置成功,0表示设置失败或者键不存在)

      ②setex命令:setex key seconds value(设置键的同时,直接设置过期时间)

      expire命令的seconds单位为秒,最小精确至1秒,如果想要更精确的控制键的过期时间,可以使用pexpire命令,pexpire命令的单位是毫秒。pexpire key 1000 与expire key 1 相等

    Redis键值过期删除原理

    Redis 删除失效主键的方法主要有两种:

    ①消极方法(passive way):

       在主键被访问时,如果发现它已经失效,那么就删除它。此处有一个问题就是:对于那些从未被查询过的key,即使它们已经过期,该方法也无法删除该过期key

    ②积极方法(active way):

       周期性的从设置了失效时间的 key 中,选择一部分失效的 key 进行删除操作。因此Redis会周期性的随机测试一些key,已过期的key将会被删除。Redis每秒会进行10次操作,根据键的过期比例,使用快慢两种速率回收键,具体的流程:

      1.随机的测试20个带有timeout(过期时间)信息的key;

      2.删除其中已经过期的key;

      3.如果超过25%的key被删除,则重复执行步骤1


2.Redis淘汰策略

       Redis中提供了多种内存回收策略,当内存容量不足时,为了保证程序的运行,这时就不得不淘汰内存中的一些对象,释放这些对象占用的空间。

       Redis的淘汰策略,是指当内存使用达到maxmemory极限时,需要使用LAU淘汰算法来决定清理掉哪些数据,以保证新数据的存入,那么选择淘汰哪些对象呢?

       maxmemory用来设置redis存放数据的最大的内存大小,一旦超出这个内存大小之后,就会立即使用Redis的淘汰策略,来清理掉部分数据。

       对于64 bit的机器,如果maxmemory设置为0,那么就默认不限制内存的使用,直到耗尽机器中所有的内存为止;,但是对于32 bit的机器,有一个隐式的闲置就是3GB。

      在Redis的配置文件redis.conf中,我们能够找到下面这样一段话:

# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select among five behaviors:
#
# volatile-lru -> Evict using approximated LRU among the keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU among the keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key among the ones with an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
#
# LRU means Least Recently Used
# LFU means Least Frequently Used
#
# Both LRU, LFU and volatile-ttl are implemented using approximated
# randomized algorithms.
#
# Note: with any of the above policies, Redis will return an error on write
#       operations, when there are no suitable keys for eviction.
#
#       At the date of writing these commands are: set setnx setex append
#       incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
#       sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
#       zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
#       getset mset msetnx exec sort
#
# The default is:
#
# maxmemory-policy noeviction

LRU 表示最近最少使用
LFU 表示最不常用

        我们可以看到,Redis淘汰默认的是noeviction策略,即当内存达到阈值的时候,所有引起申请内存的命令会报错。如果我们有其他需求,可以通过修改maxmemory-policy属性,来修改Redis淘汰键值使用的策略。那么有哪些淘汰策略供我们选择呢?Redis都在redis.conf配置文件中给我们罗列出来了。共有如下8种淘汰策略:

       1.volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,使用LRU算法,移除最近最少使用的key;

       2.allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,使用LRU算法,移除最近最少使用的key;

       3.volatile-lfu:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,使用LFU算法,移除最近最少使用的key;

       4.allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,使用LFU算法,移除最近最少使用的key;

       5.volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key;

       6.allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key;

       7.volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除;

       8.noeviction(默认):当内存不足以容纳新写入数据时,新写入操作会报错。

淘汰策略执行步骤:

      1.客户端执行数据写入操作;

      2.redis server接收到写入操作之后,检查maxmemory的限制,如果超过了限制,那么就根据对应的policy清理掉部分数据;

      3.写入操作完成执行

总结:

       实际上Redis实现的LRU并不是可靠的LRU,也就是名义上我们使用LRU算法淘汰内存数据,但是实际上被淘汰的键并不一定是真正的少使用的数据,这里涉及到一个权衡的问题,如果需要在所有的数据中搜索符合条件的数据,那么一定会增加系统的开销,Redis是单线程的,所以耗时的操作会谨慎一些。为了在一定成本内实现相对的LRU,早期的Redis版本是基于采样的LRU,也就是放弃了从所有数据中搜索解改为采样空间搜索优解。Redis3.0 版本之后,Redis作者对于基于采样的LRU进行了一些优化,目的是在一定的成本内让结果更靠近真实的LRU

END

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐