过期策略和淘汰策略
过期策略
定期删除 + 惰性删除
(1) 定期删除:redis默认每隔100ms(运行频率由配置文件中的hz参数来控制,取值范围1~500,默认是10,代表每秒运行10次)执行后台删除任务。
清理过程如下:
- 遍历所有的db
- 从db中设置了过期时间的key的集合中随机检查20个key
- 删除检查中发现的所有过期key
- 如果检查结果中25%以上的key已过期,则继续重复执行步骤2-3,否则继续遍历下一个db
调大hz将会提高redis定期任务的执行频率,如果你的redis中包含很多过期key的话,可以考虑将这个值调大,但要注意同时也会增加CPU的压力,redis作者建议这个值不要超过100。
(2) 惰性删除:定期删除可能导致很多过期的key 到了时间并没有被删除掉。这时就要使用到惰性删除。在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间并且过期了就删除,并返回nil给客户端。
定时删除
在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除。就是我们通常使用的expire(key,time)方法。这种方式的优点是,当键值过期时,内存能够及时的被释放,但是缺点是,如果同时有大量的键值同时过期(缓存雪崩),需要更多的CPU内存去删除这些键值,删除这些key会占用很多的CPU时间,很严重的影响性能。
为什么不用定时删除策略呢?
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略。
定期删除 + 惰性删除存在的问题
如果某个key过期后,定期删除没删除成功,然后也没再次去请求key,也就是说惰性删除也没生效。这时,如果大量过期的key堆积在内存中,redis的内存会越来越高,导致redis的内存块耗尽。那么就应该采用内存淘汰机制。
强制删除
LRU和LFU都是内存管理的页面置换算法。
- LRU:最近最少使用(最长时间)淘汰算法(Least Recently Used)。LRU是淘汰最长时间没有被使用的页面。
- LFU:最不经常使用(最少次)淘汰算法(Least Frequently Used)。LFU是淘汰一段时间内,使用次数最少的页面。
如果redis使用的内存已经达到maxmemory(默认值为0,上限取决于物理内存)配置的值时,会触发强制清理策略,清理策略由配置文件的maxmemory-policy参数来控制,有以下这些清理策略:
- volatile-lru:使用LRU算法对设置了过期时间的key进行清理(默认值)
- allkeys-lru:使用LRU算法对所有key进行清理
- volatile-lfu:使用LFU算法对设置了过期时间的key进行清理(redis 4.0版本开始支持)
- allkeys-lfu:使用LFU算法对所有key进行清理(redis 4.0版本开始支持)
- volatile-random:对所有设置了过期时间的key进行随机清理
- allkeys-random:从所有key进行随机清理
- volatile-ttl:清理生存时间最小的一部分key
- noeviction:不做任何清理,拒绝执行所有的写操作
为了节省内存和性能上的考虑,上述的清理策略都不需要遍历所有数据,而是采用随机采样的方法,每次随机取出特定数量(由maxmemory-samples配置项控制,默认是5个)的key,然后在这些key中执行清理策略。
注:这个清理过程是阻塞的,直到清理出足够的内存空间才会停止。
生产环境配置的淘汰策略?
maxmemory-policy=volatile-lru
生产环境的后台删除任务运行频率
hz=10,一秒10次运行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通