0%

redis-过期、淘汰

key过期-删除策略

定时删除

1
2
3
4
5
6
含义:
在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除
优点:
保证内存被尽快释放
缺点:
若过期key很多,删除这些key会占用很多的CPU时间,在CPU时间紧张的情况下,CPU不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些key定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重

惰性删除

1
2
3
4
5
6
含义:
key过期的时候不删除,每次通过key获取值的时候去检查是否过期,若过期,则删除,返回null(用的时候再检查删除)。
优点:
删除操作只在通过key取值的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的.
缺点:
若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)

定期删除

1
2
3
4
5
6
含义:
每隔一段时间执行一次删除过期key操作
优点:
通过限制删除操作的时长和频率,该策略是前两者的一个折中方案
缺点:
在内存友好方面,不如"定时过期"(会造成一定的内存占用,但是没有“惰性过期”那么占用内存)在CPU时间友好方面,不如"惰性过期"(会定期的去进行比较和删除操作,cpu方面不如“惰性过期”,但是比“定时过期”好)

Redis中同时使用了惰性过期和定期过期两种过期策略。

内存不足-淘汰策略

redis内存满了使用的淘汰策略

​ 设置maxmemory为0代表没有内存限制。对于64位的系统这是个默认值,对于32位的系统默认内存限制为3GB。
当指定的内存限制大小达到时,需要选择不同的行为,也就是策略。 Redis可以仅仅对命令返回错误,这将使得内存被使用得更多,或者回收一些旧的数据来使得添加数据时可以避免内存限制。

​ 当maxmemory限制达到的时候Redis会使用的行为由 Redis的maxmemory-policy配置指令来进行配置。

以下的策略是可用的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# volatile-lru -> 
Evict using approximated LRU, only keys with an expire set.
在过期集合的键中,尝试回收最久未被访问的键(LRU),使得新添加的数据有空间存放。
# allkeys-lru ->
Evict any key using approximated LRU.
在所有的键中,尝试回收最久未被访问的键(LRU),使得新添加的数据有空间存放。
# volatile-lfu ->
Evict using approximated LFU, only keys with an expire set.
在过期集合的键中,驱逐使用频率最少的键(LFU),使得新添加的数据有空间存放。
# allkeys-lfu ->
Evict any key using approximated LFU.
在所有的键中,驱逐使用频率最少的键(LFU),使得新添加的数据有空间存放。
# volatile-random ->
Remove a random key having an expire set.
在过期集合的键中,随机回收键,使得新添加的数据有空间存放。
# allkeys-random ->
Remove a random key, any key.
在所有的键中,随机回收键,使得新添加的数据有空间存放。
# volatile-ttl ->
Remove the key with the nearest expire time (minor TTL)
在过期集合的键,优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
# noeviction ->
Don't evict anything, just return an error on write operations.
不淘汰,返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)

一般的经验规则:

  • 使用allkeys-lru策略:当你希望你的请求符合一个幂定律分布,也就是说,你希望部分的子集元素将比其它其它元素被访问的更多。如果你不确定选择什么,这是个很好的选择。.
  • 使用allkeys-random:如果你是循环访问,所有的键被连续的扫描,或者你希望请求分布正常(所有元素被访问的概率都差不多)。
  • 使用volatile-ttl:如果你想要通过创建缓存对象时设置TTL值,来决定哪些对象应该被过期。

当想要单一的实例实现缓存及持久化一些键时,allkeys-lru 和 volatile-random策略很有用。不过一般运行两个实例是解决这个问题的更好方法。
当内存有压力时,没有必要为键取设置过期时间,因为为了键设置过期时间也是需要消耗内存的。