多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] ## 缓存的常见过期策略有哪些? ### 常见的删除策略有3种 #### 1. 定时删除 在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作。 定时删除策略通过使用定时器,定时删除策略可以保证过期键尽可能快地被删除,并释放过期键占用的内存。 因此,定时删除策略的优缺点如下所示: 1. 优点:对内存非常友好 2. 缺点:对CPU时间非常不友好 举个例子,如果有大量的命令请求等待服务器处理,并且服务器当前不缺少内存,如果服务器将大量的CPU时间用来删除过期键,那么服务器的响应时间和吞吐量就会受到影响。 也就是说,如果服务器创建大量的定时器,服务器处理命令请求的性能就会降低, 因此Redis目前并没有使用定时删除策略。 #### 2. 惰性删除 放任过期键不管,每次从键空间中获取键时,检查该键是否过期,如果过期,就删除该键,如果没有过期,就返回该键。 惰性删除策略只会在获取键时才对键进行过期检查,不会在删除其它无关的过期键花费过多的CPU时间。 因此,惰性删除策略的优缺点如下所示: 1. 优点:对CPU时间非常友好 2. 缺点:对内存非常不友好 举个例子,如果数据库有很多的过期键,而这些过期键又恰好一直没有被访问到,那这些过期键就会一直占用着宝贵的内存资源,造成资源浪费。 #### 3. 定期删除 每隔一段时间,程序对数据库进行一次检查,删除里面的过期键,至于要删除哪些数据库的哪些过期键,则由算法决定。 定期删除策略是定时删除策略和惰性删除策略的一种整合折中方案。 定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响,同时,通过定期删除过期键,也有效地减少了因为过期键而带来的内存浪费。 其中定时删除和定期删除为主动删除策略,惰性删除为被动删除策略。 ## redis中使用的过期删除策略是什么? 两种策略,定期删除和惰性删除。 定期删除是定时扫描过期时间的 key的字典删除到期的 key。惰性删除是在客户端访问这个key的时候,redis对key的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西。 定期删除是集中处理,惰性删除是零散处理。 ### **定期删除** redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的 key。 Redis 默认会每秒进行十次过期扫描(100ms一次),过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。 1.从过期字典中随机 20 个 key; 2.删除这 20 个 key 中已经过期的 key; 3.如果过期的 key 比率超过 1/4,那就重复步骤 1; redis默认是每隔 100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载。 ### **惰性删除** 所谓惰性策略就是在客户端访问这个key的时候,redis对key的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西。 定期删除可能会导致很多过期key到了时间并没有被删除掉。所以就有了惰性删除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那个 key,才会被redis给删除掉。这就是所谓的惰性删除,即当你主动去查过期的key时,如果发现key过期了,就立即进行删除,不返回任何东西. ## redis支持的内存淘汰策略有哪些? 1. **no-eviction**:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。 2. **volatile-ttl**:从已设置过期时间的数据集(server.db\[i\].expires)中挑选将要过期的数据淘汰; 3. **volatile-random**:从已设置过期时间的数据集(server.db\[i\].expires)中任意选择数据淘汰; 4. **allkeys-lru**:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key; 5. **allkeys-random**:从数据集(server.db\[i\].dict)中任意选择数据淘汰; 6. **volatile-lru**:从已设置过期时间的数据集(server.db\[i\].expires)中挑选最近最少使用的数据淘汰; 4.0 版本后增加以下两种: 7. **volatile-lfu**:从已设置过期时间的数据集(server.db\[i\].expires)中挑选最不经常使用的数据淘汰; 8. **allkeys-lfu**:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key。 > 注意:系统默认**no-eviction**。 > 当使用volatile-lru、volatile-random、volatile-ttl这三种策略时,如果没有key可以被淘汰,则和noeviction一样返回错误。 ## 关于使用这6种策略,开发者还需要根据自身系统特征,正确选择或修改。 * 在Redis中,数据有一部分访问频率较高,其余部分访问频率较低,或者无法预测数据的使用频率时,设置allkeys-lru是比较合适的。 * 如果所有数据访问概率大致相等时,可以选择allkeys-random。 * 如果研发者需要通过设置不同的ttl来判断数据过期的先后顺序,此时可以选择volatile-ttl策略。 * 如果希望一些数据能长期被保存,而一些数据可以被淘汰掉时,选择volatile-lru或volatile-random都是比较不错的。 * 由于设置expire会消耗额外的内存,如果计划避免Redis内存在此项上的浪费,可以选用allkeys-lru 策略,这样就可以不再设置过期时间,高效利用内存了。 ## LRU和LFU的区别 LRU是最近最少使用页面置换算法(Least Recently Used),也就是首先淘汰最长时间未被使用的页面! LFU是最近最不常用页面置换算法(Least Frequently Used),也就是淘汰一定时期内被访问次数最少的页! 比如,第二种方法的时期T为10分钟,如果每分钟进行一次调页,主存块为3,若所需页面走向为2 1 2 1 2 3 4 注意,当调页面4时会发生缺页中断 若按LRU算法,应换页面1(1页面最久未被使用) 但按LFU算法应换页面3(十分钟内,页面3只使用了一次) 可见LRU关键是看页面最后一次被使用到发生调度的时间长短, 而LFU关键是看一定时间段内页面被使用的频率! ## 什么是LRU(高频问题)? **介绍** LRU(Least Recently Used),即最近最少使用,是一种缓存置换算法。 **背景** 在使用内存作为缓存的时候,缓存的大小一般是固定的。当缓存被占满,这个时候继续往缓存里面添加数据,就需要淘汰一部分老的数据,释放内存空间用来存储新的数据。这个时候就可以使用LRU算法了。 **核心思想** 如果一个数据在最近一段时间没有被用到,那么将来被使用到的可能性也很小,所以就可以被淘汰掉。 **标准LRU实现方式** ![](https://img.kancloud.cn/bc/2d/bc2dfcfc769158908c48335b624a02c3_718x960.png) ## redis是如何判断数据是否过期的呢? Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。 ## redis的内存淘汰策略是什么? > 首先,需要知道,内存淘汰策略和过期键删除,是两码事儿。 因为不管是定期采样删除还是惰性删除都不是一种完全精准的删除,就还是会存在key没有被删除掉的场景,可以理解为:**内存淘汰策略是过期键删除策略的补充**。 ## 怎么解释过期键删除策略和内存淘汰机制之间的关系? * 过期键删除策略强调的是对过期健的操作,如果有键过期了,而内存还足够,不会使用内存淘汰机制,这时也会使用过期键删除策略删除过期键。 * 内存淘汰机制强调的是对内存的操作,如果内存不够了,即使有的键没有过期,也要删除一部分,同时也针对没有设置过期时间的键。