Login
网站首页 > 文章中心 > 其它

谈谈 Redis 的过期策略_Redis的过期键有哪些删除策略

作者:小编 更新时间:2023-08-15 08:06:24 浏览量:284人看过

在日常开发中,我们使用 Redis 存储 key 时通常会设置一个过期时间,但是 Redis 是怎么删除过期的 key,而且 Redis 是单线程的,删除 key 会不会造成阻塞.要搞清楚这些,就要了解 Redis 的过期策略和内存淘汰机制.

谈谈 Redis 的过期策略_Redis的过期键有哪些删除策略-图1

Redis采用的是定期删除 + 懒惰删除策略.

定期删除策略

Redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,默认每 100ms 进行一次过期扫描:

从库的过期策略

从库不会进行过期扫描,从库对过期的处理是被动的.主库在 key 到期时,会在 AOF 文件里增加一条 del 指令,同步到所有的从库,从库通过执行这条 del 指令来删除过期的 key.因为指令同步是异步进行的,所以主库过期的 key 的 del 指令没有及时同步到从库的话,会出现主从数据的不一致,主库没有的数据在从库里还存在.

懒惰删除策略

unlink

unlink 指令,它能对删除操作进行懒处理,丢给后台线程来异步回收内存.

谈谈 Redis 的过期策略_Redis的过期键有哪些删除策略-图2

>?unlink?key

flush

>?flushall?async

异步队列

主线程将对象的引用从「大树」中摘除后,会将这个 key 的内存回收操作包装成一个任务,塞进异步任务队列,后台线程会从这个异步队列中取任务.任务队列被主线程和异步线程同时操作,所以必须是一个线程安全的队列.不是所有的 unlink 操作都会延后处理,如果对应 key 所占用的内存很小,延后处理就没有必要了,这时候 Redis 会将对应的 key 内存立即回收,跟 del 指令一样.

更多异步删除点

slave-lazy-flush 从库接受完 rdb 文件后的 flush 操作

lazyfree-lazy-eviction 内存达到 maxmemory 时进行淘汰

lazyfree-lazy-expire key 过期删除

lazyfree-lazy-server-del rename 指令删除 destKey

内存淘汰机制

Redis 的内存占用会越来越高.Redis 为了限制最大使用内存,提供了 redis.conf 中的配置参数 maxmemory.当内存超出 maxmemory,Redis 提供了几种内存淘汰机制让用户选择,配置 maxmemory-policy:

noeviction:当内存超出 maxmemory,写入请求会报错,但是删除和读请求可以继续.(使用这个策略,疯了吧)

allkeys-lru:当内存超出 maxmemory,在所有的 key 中,移除最少使用的key.只把 Redis 既当缓存是使用这种策略.(推荐).

allkeys-random:当内存超出 maxmemory,在所有的 key 中,随机移除某个 key.(应该没人用吧)

volatile-lru:当内存超出 maxmemory,在设置了过期时间 key 的字典中,移除最少使用的 key.把 Redis 既当缓存,又做持久化的时候使用这种策略.

volatile-random:当内存超出 maxmemory,在设置了过期时间 key 的字典中,随机移除某个key.

volatile-ttl:当内存超出 maxmemory,在设置了过期时间 key 的字典中,优先移除 ttl 小的.

LRU 算法

实现 LRU 算法除了需要 key/value 字典外,还需要附加一个链表,链表中的元素按照一定的顺序进行排列.当空间满的时候,会踢掉手机号购买平台地图链表尾部的元素.当字典的某个元素被访问时,它在链表中的位置会被移动到表头.所以链表的元素排列顺序就是元素最近被访问的时间顺序.使用 Python 的 OrderedDict(双向链表 + 字典) 来实现一个简单的 LRU 算法:

from?collections?import?OrderedDict

class?LRUDict(OrderedDict):

?def?__init__(self,?capacity):

??self.capacity?=?capacity

??self.items?=?OrderedDict()

?def?__setitem__(self,?key,?value):

??old_value?=?self.items.get(key)

??if?old_value?is?not?None:

??self.items.pop(key)

??self.items[key]?=?value

??elif?len(self.items)? ??self.items[key]?=?value

??else:

??self.items.popitem(last=True)

??self.items[key]?=?value

?def?__getitem__(self,?key):

??value?=?self.items.get(key)

??if?value?is?not?None:

??self.items.pop(key)

??self.items[key]?=?value

??return?value

?def?__repr__(self):

??return?repr(self.items)

d?=?LRUDict(10)

for?i?in?range(15):

?d[i]?=?i

近似 LRU 算法

LFU

//?redis?的对象头

typedef?struct?redisObject?{

?unsigned?type:4;?//?对象类型如?zset/set/hash?等等

?unsigned?encoding:4;?//?对象编码如?ziplist/intset/skiplist?等等

?unsigned?lru:24;?//?对象的「热度」

?int?refcount;?//?引用计数

?void?*ptr;?//?对象的?body

以上就是土嘎嘎小编为大家整理的谈谈 Redis 的过期策略相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!

版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载、或以其他方式使用本站《原创》内容,违者将追究其法律责任。本站文章内容,部分图片来源于网络,如有侵权,请联系我们修改或者删除处理。

编辑推荐

热门文章