Redis-设置过期时间及淘汰策略
项目组使用的 Redis 服务器发出了内存不足报警,查了一些资料,记录下。
1. TTL
查看 Redis key 是否过期是 TTL 命令,或者登陆 Redis 客户端,打开 key 之后右上角显示的 TTL,Redis 官方文档描述
TTL key
起始版本:1.0.0
时间复杂度:O(1)
返回key剩余的过期时间。 这种反射能力允许Redis客户端检查指定key在数据集里面剩余的有效期。
在Redis 2.6和之前版本,如果key不存在或者已过期时返回-1。
从Redis2.8开始,错误返回值的结果有如下改变:
如果key不存在或者已过期,返回 -2
如果key存在并且没有设置过期时间(永久有效),返回 -1 。
另见PTTL命令返回相同的信息,只不过他的时间单位是毫秒(仅适用于Redis 2.6及更高版本)。
返回值
Integer reply: key有效的秒数(TTL in seconds),或者一个负值的错误 (参考上文)。
例子
redis> SET mykey "Hello"
OK
redis> EXPIRE mykey 10 # 设置mykey 10秒后过期
(integer) 1
redis> TTL mykey # 查看mykey剩余的过期时间
(integer) 10
redis>
经过了解,发现项目中许多 Redis key 并未设置过期时间。
(图源网络,侵删)
2. 设置过期时间
在使用 Redis 存储数据的时候,有些数据可能在某个时间点之后就不再有用了,用户可以用 DEL 命令显式地删除这些无用的数据,也可以通过 Redis 的过期时间(expiration)特性来让一个键在给定的时限(timeout)之后自动删除。
用于处理过期时间的 Redis 命令
命令 | 示例和描述 |
---|---|
PERSIST | PERSIST key-name :移除键的过期时间 |
TTL | TTL key-name :查看给定键距离过期还有多少秒 |
EXPIRE | EXPIRE key-name seconds :让给定键在指定的秒数之后过期 |
EXPIREAT | EXPIREAT key-name timestamp :将给定键的过期时间设置为给定的 UNIX 时间戳 |
PTTL | PTTL key-name :查看给定键距离过期还有多少毫秒,Redis 2.6或以上版本可用 |
PEXPIRE | PEXPIRE key-name milliseconds :让给定键在指定的毫秒数之后过期,2.6或以上可用 |
PEXPIREAT | PEXPIREAT key-name timestamp-milliseconds :将给定键的过期时间设置为给定的毫秒级精度 UNIX 时间戳,2.6或以上可用 |
3. 删除过期key
那么问题来了,即使设置了过期时间,key 过期之后,不删除的话还是占着内存的。
redis中文文档 http://www.redis.cn/documentation.html
中有这段描述
Redis如何淘汰过期的keys
Redis keys过期有两种方式:被动和主动方式。
当一些客户端尝试访问它时,key会被发现并主动的过期。
当然,这样是不够的,因为有些过期的keys,永远不会访问他们。 无论如何,这些keys应该过期,所以定时随机测试设置keys的过期时间。所有这些过期的keys将会从密钥空间删除。
具体就是Redis每秒10次做的事情:
1. 测试随机的20个keys进行相关过期检测。
2. 删除所有已经过期的keys。
3. 如果有多于25%的keys过期,重复步奏1.
这是一个平凡的概率算法,基本上的假设是,我们的样本是这个密钥控件,并且我们不断重复过期检测,直到过期的keys的百分百低于25%,这意味着,在任何给定的时刻,最多会清除1/4的过期keys。
以上描述中,被动方式就是常说的惰性删除:数据到达过期时间,不做处理。等下次访问该数据时,如果未过期,返回数据 ;发现已过期,删除,返回不存在(nil)。
主动方式就是常说的定期删除:
Redis 每秒10次。。。。这个10次由 redis.conf 中 hz 控制,默认是10。hz的取值范围为1~500。增大hz参数的值会提升各项定期任务的执行频率,超时处理会更加精准。但也会提高Redis服务的CPU使用率。默认值10在一般情况下已经可以满足需求,如果业务场景对于某些定期任务的执行频率有很高的要求,您可以尝试在100以内调整参数值。
—PS:我这 redis 3.2.8 设置了这个参数没有生效,不知道为啥
还有就是定时删除:写功能将过期的 key 全删除了,十分耗费资源,不推荐。
4. 淘汰策略
Redis 即使设置了过期时间和删除方式,也会出现在插入新 key 时,内存不足的问题,这需要设置淘汰策略,将一些数据删除。
Redis 中文文档中,有下面的描述:
配置Redis成为一个缓存
如果你想把Redis当做一个缓存来用,所有的key都有过期时间,那么你可以考虑 使用以下设置(假设最大内存使用量为2M):
```
maxmemory 2mb
maxmemory-policy allkeys-lru
```
以上设置并不需要我们的应用使用EXPIRE(或相似的命令)命令去设置每个key的过期时间,因为 只要内存使用量到达2M,Redis就会使用类LRU算法自动删除某些key。
相比使用额外内存空间存储多个键的过期时间,使用缓存设置是一种更加有效利用内存的方式。而且相比每个键固定的 过期时间,使用LRU也是一种更加推荐的方式,因为这样能使应用的热数据(更频繁使用的键) 在内存中停留时间更久。
这其中涉及到3个 redis.conf 参数
maxmemory
当redis使用内存达到设定值时触发淘汰策略
maxmemory-samples
触发淘汰策略时,每次选取的key的数量,默认值是5,如果增加,会提高LRU或TTL的精准度,redis作者测试的结果是当这个配置为10时已经非常接近全量LRU的精准度了,另外增加这个值会在主动清理时消耗更多的CPU时间。
maxmemory-policy
淘汰策略,有以下8种:
1)noeviction: 不删除,直接返回报错信息。
2)allkeys-lru:移除最久未使用(使用频率最少)使用的key。
3)volatile-lru:在设置了过期时间的key中,移除最久未使用的key。
4)allkeys-random:随机移除某个key。
5)volatile-random:在设置了过期时间的key中,随机移除某个key。
6)volatile-ttl: 在设置了过期时间的key中,移除准备过期的key。
7)allkeys-lfu:移除最近最少使用的key。
8)volatile-lfu:在设置了过期时间的key中,移除最近最少使用的key。
注意这个检测范围是 maxmemory-samples 定义的值,并不是全库。