本文是大数据系列第 47 篇,深入讲解 Redis 如何通过过期键管理和内存淘汰策略控制内存使用,确保服务稳定运行。

完整图文版(含截图):CSDN 原文 | 掘金

Redis 性能基准

在理想条件下,Redis 的性能参考值:

  • 读操作:约 110,000 次/秒
  • 写操作:约 81,000 次/秒

实际性能受网络延迟、数据结构复杂度等因素影响。这一高性能背后,内存管理是保障系统稳定的关键。

maxmemory 配置

未设置 maxmemory(默认值 0)

Redis 不限制内存使用,当系统物理内存耗尽时:

  • 默认策略为 noeviction,拒绝所有写操作并返回 OOM 错误
  • 适用于 key 数量可预测、数据不可丢失的场景

设置 maxmemory

# redis.conf 中配置
maxmemory 1024mb

# 运行时查询
CONFIG GET maxmemory

内存达到上限后,Redis 会根据 maxmemory-policy 自动淘汰数据。

键过期机制

设置过期时间

EXPIRE key seconds       # 设置秒级 TTL
PEXPIRE key milliseconds # 设置毫秒级 TTL
EXPIREAT key timestamp   # 在指定 UNIX 时间戳过期

TTL key   # 查询剩余秒数(-1 表示永不过期,-2 表示键不存在)
PTTL key  # 查询剩余毫秒数

过期键的典型应用场景

场景推荐 TTL
验证码5-10 分钟
登录 Session30 分钟 ~ 数小时
数据库查询缓存根据业务波动设定
分布式锁业务处理时间 + 缓冲
API 限流计数器时间窗口大小

三种删除策略

Redis 采用惰性删除 + 主动定期删除的组合策略,兼顾 CPU 和内存的使用效率。

1. 惰性删除(Lazy Deletion)

键过期后不立即删除,等下次访问时检查是否已过期,过期则删除并返回空值。

  • 优点:节省 CPU,不做无效扫描
  • 缺点:过期键可能长期占用内存(尤其是从不被访问的 key)

2. 主动定期删除(Active Expiry)

Redis 周期性随机抽查一批带有 TTL 的 key,删除其中已过期的条目。频率由 hz 参数控制(默认每秒 10 次)。

  • 优点:能清理”僵尸键”,控制内存增长
  • 缺点:无法保证所有过期键都被及时清理

3. 定时删除(Scheduled Deletion)

为每个 key 创建一个定时器,到期立即删除。因为要为每个 key 维护定时器,CPU 开销极大,Redis 实际未使用此策略

内存淘汰策略

当内存达到 maxmemory 上限且无法继续申请内存时,Redis 按 maxmemory-policy 决定如何淘汰数据。

maxmemory-policy allkeys-lru

8 种策略对比

策略淘汰范围淘汰算法说明
noeviction拒绝写操作(默认)
allkeys-lru全部 keyLRU淘汰最久未使用的 key
volatile-lru有过期时间的 keyLRU在设有 TTL 的 key 中 LRU
allkeys-lfu全部 keyLFU淘汰访问频率最低的 key
volatile-lfu有过期时间的 keyLFU在设有 TTL 的 key 中 LFU
allkeys-random全部 key随机随机淘汰任意 key
volatile-random有过期时间的 key随机随机淘汰带 TTL 的 key
volatile-ttl有过期时间的 keyTTL优先淘汰剩余存活时间最短的 key

LRU 实现原理

Redis 并非维护严格的 LRU 链表,而是为每个 key 记录最后访问时间戳(lru_clock,精度为秒)。淘汰时随机抽取若干个 key(maxmemory-samples 控制样本数),选出其中 LRU 值最大(最久未访问)的 key 删除。这是一种近似 LRU,在节省内存的同时效果接近精确 LRU。

LFU 实现原理

LFU(Least Frequently Used)淘汰访问频率最低的 key,比 LRU 更能抵抗偶发的批量访问对热点判断的干扰。Redis 6.0 引入 LFU,使用 Morris Counter 对访问频率进行概率计数,并加入时间衰减因子,避免历史热 key 永远不被淘汰。

策略选型建议

场景推荐策略
不确定数据访问模式allkeys-lru(最通用)
有明显冷热数据分区allkeys-lruallkeys-lfu
所有数据重要性均等allkeys-random
业务已为 key 设置合理 TTLvolatile-ttl
缓存数据不可丢失noeviction(需配合告警扩容)

生产实践建议

  • 生产环境必须设置 maxmemory,避免 Redis OOM 影响宿主机其他服务
  • 开启内存淘汰前,先用 INFO memory 监控 used_memorymaxmemory_human
  • 结合业务特征为 key 设置合理的 TTL,减少淘汰算法的压力
  • 使用 maxmemory-samples 调大样本数(如 10)可提升 LRU 精度,但会增加 CPU 开销