☰
Redis内存管理:过期删除与淘汰策略详解
2026/11/2 13:53:32 网站建设 项目流程

1. Redis过期删除与内存淘汰的本质区别

Redis作为内存数据库,面临两个核心问题:如何清理过期数据?内存不足时如何淘汰数据?这是两个完全不同的机制,但很多开发者容易混淆。

过期删除策略针对的是那些已经设置了过期时间(TTL)的键值对。Redis会在这些键过期后自动删除它们,这是Redis提供的一种主动清理机制。而内存淘汰策略是当Redis内存使用达到maxmemory限制时,按照特定算法选择一些键进行删除以释放空间。

关键区别:过期删除是"时间驱动"的,内存淘汰是"空间驱动"的。

举个例子,假设Redis中有一个键user:1001:session设置了30分钟过期时间。30分钟后,即使内存还很充足,Redis也会删除这个键——这是过期删除。而如果Redis内存快满了,可能根据LRU算法删除最近最少使用的键product:9988:cache,即使它的过期时间还没到——这就是内存淘汰。

2. Redis的过期删除策略实现细节

2.1 惰性删除(Lazy Expiration)

当客户端尝试访问一个键时,Redis会先检查该键是否已过期。如果过期就立即删除,然后返回空值。这种策略的优点是节省CPU资源,只在必要时才检查过期。

但缺点也很明显:如果大量过期键长期不被访问,它们会一直占用内存。我曾经在生产环境遇到一个案例:某电商系统每天生成数百万临时促销键,设置24小时过期。由于促销结束后无人访问这些键,导致Redis内存持续增长,直到触发内存淘汰。

2.2 定期删除(Active Expiration)

Redis会每隔一段时间(默认100ms)随机抽取一定数量的键(默认20个)检查过期情况。通过调整hz参数可以改变检查频率,但过高会影响性能。

定期删除采用自适应算法:如果发现过期键比例超过25%,会立即进行下一轮检查。这种策略是对惰性删除的补充,但仍然无法保证完全及时清理。

实战建议:对于过期键密集的场景,可以适当调高hz值(如20),但需要监控CPU使用率。

3. Redis内存淘汰策略详解

当内存达到maxmemory限制时,Redis提供了8种淘汰策略:

3.1 不淘汰策略

  • noeviction(默认):拒绝所有写入请求,只允许读操作。适合数据绝对不能丢失的场景。

3.2 仅淘汰过期键

  • volatile-random:随机删除设置了过期时间的键
  • volatile-ttl:优先删除剩余生存时间(TTL)最短的键
  • volatile-lru:删除最近最少使用的过期键
  • volatile-lfu:删除访问频率最低的过期键

3.3 淘汰所有键

  • allkeys-random:随机删除任意键
  • allkeys-lru:删除最近最少使用的键
  • allkeys-lfu:删除访问频率最低的键

4. LRU与LFU算法的实现原理

4.1 LRU(最近最少使用)算法

Redis采用近似LRU算法,通过采样而非全量扫描来平衡性能与精度。关键参数maxmemory-samples(默认5)控制采样数量。

算法过程:

  1. 维护一个淘汰候选池(大小16)
  2. 每次需要淘汰时,随机选取maxmemory-samples个键
  3. 将其中最久未访问的键放入候选池
  4. 从候选池中淘汰真正的LRU键
# 简化的LRU实现 class LRUCache: def __init__(self, capacity): self.capacity = capacity self.cache = OrderedDict() def get(self, key): if key not in self.cache: return -1 self.cache.move_to_end(key) return self.cache[key] def put(self, key, value): if key in self.cache: self.cache.move_to_end(key) self.cache[key] = value if len(self.cache) > self.capacity: self.cache.popitem(last=False)

4.2 LFU(最不经常使用)算法

Redis 4.0引入LFU算法,考虑访问频率而非最近访问时间。每个键维护一个计数器:

  • 每次访问时计数器递增
  • 计数器会随时间衰减

LFU更适合热点数据明显的场景,比如新闻热点排行榜。配置示例:

maxmemory-policy allkeys-lfu lfu-log-factor 10 lfu-decay-time 1

5. 生产环境配置建议

5.1 策略选择指南

  • 数据重要性高且可预测访问模式:volatile-lru
  • 需要保留最新数据:allkeys-lru
  • 存在明显热点数据:allkeys-lfu
  • 数据完全不可丢失:noeviction+扩容

5.2 关键参数调优

# 内存限制(根据机器内存的70-80%设置) maxmemory 16gb # 采样数量(提高精度但增加CPU开销) maxmemory-samples 10 # LFU衰减系数(值越大衰减越慢) lfu-log-factor 10 # 主动删除频率(默认10,范围1-500) hz 20

5.3 监控指标

  • used_memory:当前内存使用量
  • evicted_keys:累计淘汰键数
  • expired_keys:累计过期键数
  • keyspace_hits/misses:缓存命中率

6. 常见问题排查案例

6.1 内存突然增长

现象:Redis内存使用率突然飙升 排查步骤:

  1. 检查info memory中的used_memory变化
  2. 分析slowlog是否有大键写入
  3. 使用redis-cli --bigkeys查找大键
  4. 确认是否大量键设置了较长TTL

6.2 频繁淘汰导致性能下降

现象:QPS下降,evicted_keys快速增长 解决方案:

  1. 调整淘汰策略为allkeys-lru
  2. 增加maxmemory-samples提高淘汰精度
  3. 考虑水平分片或升级硬件

6.3 缓存穿透问题

现象:大量请求直接打到数据库 解决方案:

  1. 对不存在的键也缓存空值(设置较短TTL)
  2. 使用布隆过滤器预判键是否存在
  3. 实现客户端本地缓存

在电商大促期间,我们曾通过组合使用allkeys-lfu策略和本地缓存,将缓存命中率从75%提升到98%,数据库负载降低80%。关键是在压测阶段就模拟真实流量模式,验证不同策略的效果。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询