0%

Redis如何有效避免内存耗尽

Redis内存设置

redis通过maxmemory配置选项来配置redis的存储数据所能使用的最大的内存限制(可以通过通过修改redis.conf或者在redis-cli中使用config set来进行配置),如果我们要配置的内存上限是100M的Redis缓存,那么我们可以在 redis.conf 配置 maxmemory 100mb

配置 maxmemory 0 表示没有内存限制(在 64-bit 系统中,默认是 0 无限制,但是在 32-bit 系统中默认是 3GB)。

当存储数据达到限制时,Redis 会根据情形选择不同策略,或者返回errors(这样会导致浪费更多的内存),或者清除一些旧数据回收内存来添加新数据。

回收策略

当内存达到限制时,Redis 具体的回收策略是通过 maxmemory-policy 配置项配置的,可选的配置项如下:

noenviction
不清除数据,只是返回错误,这样会导致浪费掉更多的内存,对大多数写命令(DEL 命令和其他的少数命令例外)。
allkeys-lru
从所有的数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰,以供新数据使用。
volatile-lru
从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰,以供新数据使用。
volatile-lfu
根据 LFU 算法删除设置了过期时间的键,直到腾出可用空间。如果没有可删除的键对象,且内存还是不够用时,则报错
allkeys-lfu
根据 LFU 算法删除所有的键,直到腾出可用空间。如果没有可删除的键对象,且内存还是不够用时,则报错
allkeys-random
从所有数据集(server.db[i].dict)中任意选择数据淘汰,以供新数据使用。
volatile-random
从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰,以供新数据使用。
volatile-ttl
从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰,以供新数据使用。

回收策略的执行过程

当客户端执行一条新的命令的时候,该命令需要导致数据库增加数据(如set key value),此时redis就会检查内存的使用情况,如果内存使用超过maxmemory设置的大小,此时就会按照执行的置换策略删除一些key,之后再去执行set key vlaue

如果我们持续的写数据会导致内存达到或超出上限 maxmemory,但是置换策略会将内存使用降低到上限以下。但是如果一次需要使用很多的内存(比如一次写入一个很大的set),那么,Redis 的内存使用可能超出最大内存限制一段时间。

Redis过期设置

要知道,redis在服务器上运行,内存不可能是无限的,在实际使用场景中,很多情况下某些键值对只会在特定的时间内有效,为了防止这种类型的数据一直占有内存,我们可以给键值对设置有效期。

Redis提供了EXPIRE以及PEXPIRE来设置过期时间:
expire key ttl: 将key值的过期时间设置为ttl秒。
pexpire key ttl: 将key值的过期时间设置为ttl毫秒。

ttl(Time To Live),表示键的生存时间,设置之后,时间会自动减少,当时间耗尽时,Redis就会移除该键。

1
2
3
当设置成功的时候返回1,失败返回0
127.0.0.1:6379> expire name 120
(integer) 1

对于已经设置过生存时间的键重新执行expire或者pexpire会使用新的ttl进行更新。

除了使用expire或者pexpire对已经创建的键的生存时间进行设置之外,字符串类型的键的设置方式set在使用的时候提供了EX以及PX参数用于设置过期的秒或者毫秒。

1
2
127.0.0.1:6379> set name tmj EX 23
OK

该方式除了可以减少命令的调用数量并提供程序的执行速度之外,更重要的是保证了操作的原子性,使得设置键以及过期时间同时执行,分开使用,先使用set name tmj创建键,之后再使用expire name 66设置过期时间,这两条命令是独立的,所以在Redis服务器在执行的时候就可以发生set执行了,但是设置过期时间的操作没有进行,此时缓存就不会自动过期,这在生产环境中是可能出现的。注意:set只能用于字符串类型的键的创建。此外过期时间的设置也是对整个键的设置,像集合、列表以及散列类型无法对其中的元素进行自动过期设置。

此外,除了设置生存时间,redis还提供了expireat以及pexpireat来设置过期时间,让Redis在指定UNIX时间来临之后自动移除给定的键,注意使用的是UNIX时间戳expireat key timestamp

过期时间查询

通过ttl key查看过期剩余时间,单位为秒,pttl key查看过期时间,单位为毫秒。

过期时间的查询结果有一下几种:
大于0的正整数:此key存在,且还剩下正整数的时间过期
-1 : 此key存在,且没有设置过期时间,即永久不会过期
-2 : 此key不存在,或存在但是过期了,总之就是现在不存在了。