Redis的数据清理机制
Redis数据清理机制主要分为两大核心体系:
- 过期键删除策略:针对设置了过期时间的Key,负责在Key过期后进行自动清理,属于"到时间清垃圾"的被动与主动结合型清理;
- 内存淘汰策略:在Redis占用内存达到预设上限时,通过主动淘汰部分Key腾出内存空间,属于"内存不够强制腾位置"的应急型清理;
二者既相互独立又协同互补,共同保障Redis在内存资源有限的情况下高效运行,既避免了过期数据长期占用内存导致的资源浪费,也防止了内存溢出引发的服务异常。
Redis过期键删除策略
什么是Redis的过期数据
Redis作为一种内存级数据库,其所有数据均存放在内存中,对于内存中的数据,我们可以通过TTL指令获取其存活状态,而TTL指令返回的值主要分为三种情况,分别对应数据的不同存活状态。
第一种情况是返回正数,该数值代表该数据在内存中还能存活的时间,也就是数据的剩余过期时间;
第二种情况是返回-1,代表该数据是永久有效的,未设置任何过期时间;
第三种情况是返回-2,代表该数据是已经过期的数据、或被手动删除的数据、或未定义的不存在的数据。
针对设置了EXPIRE/TTL过期时间的Key,Redis提供了三种明确的删除策略,每种策略对应不同的删除时机,也各有优劣。
定时删除策略
定时删除策略的删除时机核心是"Key的过期时间一到达,立即执行删除"。
具体而言,当给Key设置过期时间后,Redis会立即为该Key创建一个定时器,一旦过期时间节点到来,定时器就会触发,立即执行对该Key的删除操作。
优点是能够最大限度节约内存资源,只要Key过期就会被及时删除,快速释放不必要的内存占用,不会出现过期数据滞留内存的情况;
缺点是会给CPU带来较大压力,因为无论当前CPU是否繁忙,只要Key到达过期时间,就必须执行删除操作,这种强制触发的删除会占用CPU资源,进而影响Redis服务器的响应时间和整体性能。
综上,定时删除策略本质上是用处理器性能换取存储空间,也就是典型的"时间换空间"策略,由于其对CPU的过高消耗,在实际生产中基本不被采用。
惰性删除策略
惰性删除策略的删除时机核心是"过期不主动删除,访问时再判断删除"。
具体而言,即使Key已经到达预设的过期时间,Redis也不会主动对其进行任何处理,该Key会一直存在于内存中,直到下次客户端访问该Key(执行get指令)时,才会对其过期状态进行判断:如果Key未过期,则正常返回数据;如果Key已过期,则立即删除该Key,并返回数据不存在的响应。
需要特别注意的是,在执行get指令时,Redis会隐性地先执行expireIfNeeded()方法,以此判断数据是否已经过期。
优点是能最大限度节约CPU性能,无需后台线程持续监控所有过期Key,也不会在Key过期时强制执行删除操作,仅在有实际访问请求时才进行判断和删除,避免了无效的CPU消耗;
缺点是会给内存带来较大压力,若某个过期Key长时间不被访问,就会一直占用内存资源,导致内存利用率下降,甚至引发内存泄露问题。
综上,惰性删除策略本质上是用存储空间换取处理器性能,也就是"空间换时间"策略,能够有效降低CPU负担,但需配合其他策略缓解内存压力。
定期删除策略
定期删除策略的删除时机核心是"按固定周期,周期性地抽样检查并删除过期Key",是一种兼顾CPU和内存的折中策略。
具体实现逻辑如下:Redis启动服务器并完成初始化时,会读取配置文件中的hz参数(该参数用于控制定期删除的频率),其默认值为10,意味着Redis每秒会执行10次activeExpireCycle()方法,对每个Redis库(Redis默认有16个库,编号0-15)逐一进行检测,每次执行该方法的耗时被严格控制在250ms/10,即每次执行不超过25ms,避免阻塞主线程。在对某个Redis库进行检测时,会随机挑选w个Key进行过期检查(w的取值为ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性的默认值),检查规则为:如果被检测的Key已经超时,则立即删除该Key;如果一轮检测中,删除的Key数量超过了本次检测Key总数的25%,则继续对该Redis库循环执行抽样检测;如果一轮检测中,删除的Key数量≤本次检测Key总数的25%,则停止对该Redis库的检测,转而检查下一个Redis库,按0-15的顺序循环进行。
总结来看,定期删除策略的核心是周期轮询Redis库中的时效性数据,采用随机抽取的策略,同时利用"过期数据占比"的方式动态控制删除频度------当某个库中过期数据较多时(删除占比超过25%),会加大该库的检测力度,确保尽快清理部分过期数据;当过期数据较少时,则切换到下一个库,避免占用过多CPU资源。这种策略很好地平衡了内存和CPU的压力,既不会像惰性删除那样导致内存压力过大,也不会像定时删除那样给CPU带来过重负担,同时其检测频度可通过调整hz参数自定义设置,能够根据实际业务场景和服务器性能灵活适配。
综合三种过期键删除策略的优劣,Redis最终选择"惰性删除+定期删除"的组合方案:日常依靠惰性删除节省CPU资源,避免无效的后台扫描;后台通过定期删除按固定周期抽样清理过期Key,缓解惰性删除带来的内存浪费和内存泄露风险,实现了CPU与内存资源的动态平衡,既保证了Redis服务器的响应性能,又能有效控制内存占用。
Redis内存淘汰策略
当Redis占用的内存达到预设的maxmemory最大内存限制时,再执行写入类命令(如set、hset等)就会触发内存淘汰机制,Redis会按照预设的淘汰策略,删除一部分Key以腾出足够的内存空间,确保新数据能够正常写入;若未配置maxmemory参数,Redis会无限制占用服务器的物理内存,不会触发任何内存淘汰操作,严重时可能导致服务器内存耗尽,引发系统异常。除了maxmemory参数外,与内存淘汰相关的核心配置还有maxmemory-policy,该参数用于指定内存满时的具体淘汰策略,目前Redis共提供了六大淘汰策略,可分为三大类,分别适用于不同的业务场景。
放弃数据驱逐
第一类是放弃数据驱逐策略,即noeviction策略。这也是Redis的默认淘汰策略,其核心逻辑是当内存达到上限后,拒绝所有写入命令,此时写入操作会报错,但读命令(如get、hget等)可以正常执行;这种策略适用于数据绝对不能丢失的业务场景,如金融交易、订单存储等,这类业务不允许通过删除任何数据来腾出内存,宁愿拒绝新数据写入,也不能牺牲已存储的数据安全性。
检测全库数据
第二类是检测全库数据,从所有Key中淘汰。这类策略不区分Key是否设置了过期时间,所有Key均参与淘汰,也是缓存场景中最常用的一类策略,具体包括两种:allkeys-lru策略和allkeys-lfu策略。其中allkeys-lru策略是最常用的淘汰策略,其核心是淘汰最近最少使用的Key,通过判断Key的访问时间,优先删除长时间未被访问的冷数据;allkeys-lfu策略是Redis4.0版本新增的策略,核心是淘汰最不经常使用的Key,通过统计Key的访问频次,优先删除访问次数最少的Key,相比LRU策略,LFU更能避免"偶尔访问的冷数据常驻内存"的问题,适用范围更广泛。
检测易失数据
第三类是检测易失数据,只从带过期时间的Key中淘汰。这类策略仅在设置了TTL过期时间的Key中选择淘汰对象,永久Key(未设置过期时间的Key)永远不会被删除,具体包括四种策略:volatile-lru策略、volatile-lfu策略、volatile-random策略和volatile-ttl策略。其中volatile-lru策略是在所有带过期时间的Key中,淘汰最近最少使用的Key;volatile-lfu策略是在所有带过期时间的Key中,淘汰最不经常使用的Key;volatile-random策略则是随机删除带过期时间的Key,逻辑简单粗暴,不考虑Key的冷热程度;volatile-ttl策略则是优先删除剩余过期时间最短的Key,适用于希望优先清理即将过期的临时数据的业务场景。
综上,Redis的数据删除与内存淘汰策略是一个系统性的设计,通过"惰性删除+定期删除"的组合实现过期数据的高效清理,明确了不同策略的删除时机,平衡了CPU与内存资源;通过六大内存淘汰策略应对内存不足的场景,兼顾了CPU资源、内存利用率和服务性能。在实际应用中,需结合业务场景合理配置过期时间和内存淘汰策略,熟练掌握相关配置命令和注意事项,才能充分发挥Redis的高性能优势,保障服务的稳定运行。