redis默认删除策略,redis存储
文章前言1、过期数据删除策略1.1定时删除1.2惯性删除1.3定期删除2、内存销毁策略
前言
在将Redis用于缓存的过程中,我们一般会对key设定一定的有效期。 Redis中除了包含用于设置字符串类型特定过期日期的命令setex外,还必须依赖expire命令设置过期日期。
命令格式:
EXPIRE key ttl命令用于将键key的生存时间设置为ttl秒PEXPIRE key ttl命令用于将键key的生存时间设置为ttl毫秒EXPIREAT key timestame命令键key的生存时间为timestame指定的秒数te 用于设置为IRE的命令AT key timestame命令将密钥key的生存时间设置为由timestame指定的毫秒时间戳。 此外,persist命令还会删除密钥的过期时间。 那么再考虑一个问题吧。过期时间除了有助于缓解内存的消耗,还有什么其他么?
在很多情况下,在我们的业务场景中,某个数据必须只存在于某个时间段。 例如,我们的邮件验证码可能只在一分钟内有效,用户登录的token可能只在一天内有效。 使用传统数据库处理时,通常自己判断过期,这更麻烦,性能也更差。那么Redis是如何判断数据是否过期的呢?
最初,Redis使用过期词典(可以视为hash表)来存储数据过期的时间。 过期词典的关键
Redis数据库中的密钥。 过期词典的值为长整型整数,保存有密钥处
的数据库密钥的过期时间。 UNIX时间戳,以毫秒为单位。
过期词典存储在名为redisDb的结构中:
typedefstructredisdb { . dict * dict; //保存数据库中所有键值和dict *expires的数据库密钥区域//过期词典、密钥过期. } Redis词典类似于java的HashMap。 如果Redis词典封装了哈希表,就很容易理解了。 这部分对Redis词典的结构理解和java HashMap的区别以及阿里面试官: hashmap熟悉吗? 好的,那么谈谈Redis词典吧!
一、过期数据的删除策略如果你把批密钥设置为只能活一分钟,一分钟后,Redis是怎么删除这些密钥的呢?
Redis的过期数据删除策略分为以下三部分:
1.1定时删除计划删除策略是指每当key过期时,计时器(timer )就会启动,并在key过期后立即执行key删除操作。优点:此策略对内存非常有用,因为它在计时器到期时清除过期的密钥,并且不占用额外的内存。缺点:毫无疑问,此策略对CPU最不友好。 在过期密钥较多的情况下,删除过期密钥的行为可能会占用相当大的CPU时间,在内存不紧张但CPU时间非常紧张的情况下,会将大量的CPU时间浪费在删除过期策略上,而不是处理客户端的请求。
1.2惯性删除惯性删除策略只需在每次获取密钥时先确定expires对象中的密钥是否过期,如果已过期则删除密钥,否则返回与该密钥对应的数据。优点:此策略对CPU最容易使用,仅在取出key时对key进行过期检查。 也就是说,只有在不能时才进行删除,删除的目标仅限于当前正在处理的密钥,而不需要CPU时间删除其他无关的过期密钥。缺点:该战略的缺点是对内存最不友好。 如果一个key已过期,且该key仍留在数据库中,则除非删除该过期key,否则不会释放正在使用的内存。 例如,如果数据库中有非常多的过期密钥,且这些过期密钥未被访问,则它们可能不会被删除,除非用户手动运行flushdb命令将其清空。 因此,大量无用的脏数据占用大量内存,存在内存泄漏的风险。
1.3发现,定时删除比定期删除更不善待CPU,惯性删除会浪费内存,存在内存泄漏风险。
定期删除策略是CPU和内存消耗之间的折衷,通过每隔一定时间执行删除过期密钥的操作,限制删除操作执行的时长和频率,从而向CPU时间提供删除操作否则,删除操作可能会影响CPU时间
此类策略的最大难点是如何设置删除操作的执行时间和频率。 的设定过于频繁,会退化为定时删除,浪费大量的CPU资源,设置间隔时
间长一点,则又可能出现内存大量堆积。Redis实际上使用的是惰性删除和定期删除两种策略,通过配合使用,服务器可以很好的平衡 CPU 和内存。那么是怎么实现的呢?我们在《Redis设计与实现》中能看到:
惰性删除策略的实现:
每次取数据的时候都会调用过滤函数(db.c/expireIfNeeded),该函数主要用来判断键是否过期,如果过期,则删除键,否则,则取得对应键的值。
定期删除键的策略实现:
1、函数每次运行时,都从一定数量的数据库取出一定数量的随机键进行检查,并删除其中的过期键。
2、全局变量 current_db 会记录当前 activeExpireCycle 函数的检查进度,并在下一次 activeExpireCycle 调用时,接着上一次的进度进行处理。
3、随着 activeExpireCycle 函数的不断执行,服务器中的所有数据库都会被检查一遍,当到达最后时,把 current_db 设置为 0,然后又重新开始,如此循环下去。
但是,仅仅通过给 key 设置过期时间还是有问题的。因为还是可能存在定期删除和惰性删除漏掉
了很多过期 key 的情况。这样就导致⼤量过期 key 堆积在内存⾥,然后就Out of memory了。
怎么解决这个问题呢?答案就是: Redis 内存淘汰机制。
相关问题:MySQL ⾥有 2000w 数据,Redis 中只存 20w 的数据,如何保证 Redis 中的数
据都是热点数据?
Redis 提供 8 种数据淘汰策略:
1. volatile-lru:从已设置过期时间的数据集中挑选最近最少使⽤的数据淘汰。2. volatile-random:从已设置过期时间的数据集中任意选择数据淘汰。
3. allkeys-lru:当内存不⾜以容纳新写⼊数据时,在键空间中,移除最近最少使⽤的 key(这个是最常⽤的)
4. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰。
5. volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰。
6. no-eviction:禁⽌驱逐数据,也就是说当内存不⾜以容纳新写⼊数据时,新写⼊操作会报 错OOM。
4.0 版本后增加以下两种:
7. volatile-lfu:从已设置过期时间的数据集中挑选最不经常使⽤的数据淘汰。
8. allkeys-lfu:当内存不⾜以容纳新写⼊数据时,在键空间中,移除最不经常使⽤的 key。
相关术语解释:LRU:least recently used,LFU:least frequently used
参考文章:
1、Redis过期键删除策略
2、《JavaGuide4.0》