缓存超量怎么办——缓存容量规划与淘汰策略

缓存超量怎么办——缓存容量规划与淘汰策略

问题背景

Redis 是一个基于内存的数据库,内存是有限且昂贵的资源。当缓存数据量超过可用内存时,如果不加控制,Redis 会因 OOM(Out of Memory)被内核杀掉,或者发生大量 Swap 导致性能崩溃。

核心问题:缓存不可能无限存储,超量时必须做出取舍。

缓存容量规划

第一步:估算缓存容量

// 每条缓存数据的容量估算
// Key: "user:1001" ≈ 12 bytes
// Value: JSON字符串 ≈ 500 bytes
// Redis Dict 额外开销 ≈ 50 bytes
// 每条 ≈ 562 bytes

// 100 万用户 ≈ 562 MB
// 1000 万用户 ≈ 5.5 GB

需要考虑的系统开销:
– Redis 自身进程内存(~1MB 基础,加上持久化缓冲)
– 主从同步缓冲区(repl_backlog)
– 客户端输出缓冲区
– AOF 重写期间的内存翻倍

第二步:设置 maxmemory

# redis.conf
maxmemory 4gb
maxmemory-policy allkeys-lru

永远不要在无限制的情况下运行 Redis。

Redis 内存淘汰策略(Eviction Policies)

当内存达到 maxmemory 上限时,Redis 根据配置的策略淘汰现有数据,为新的写入腾出空间。

八种淘汰策略

策略 全称 行为 适用场景
noeviction 不淘汰 写入返回 OOM 错误 保证数据不丢,但会写失败
allkeys-lru 所有 Key LRU 淘汰最近最少使用的 key 最通用,推荐
allkeys-lfu 所有 Key LFU 淘汰使用频率最低的 key 热点温度差异明显的场景
volatile-lru 带过期 LRU 仅在设置了 TTL 的 key 中 LRU 有 TTL 的做缓存,无 TTL 的做持久化
volatile-lfu 带过期 LFU 仅在设置了 TTL 的 key 中 LFU 同上,但基于频率
allkeys-random 所有 Key 随机 随机淘汰数据 冷热分布均匀的场景
volatile-random 带过期随机 随机淘汰 TTL 的 key 不常用
volatile-ttl 带过期 TTL 淘汰剩余 TTL 最短的 key 希望快过期的先走

如何选择

80% 的场景推荐 allkeys-lru,因为:
– 自动淘汰最不常用的数据,适应大多数业务
– 不需要人工设置 TTL(当然建议设)
– 新写入的数据有机会保留,不会刚写入就被淘汰

特殊场景
– 如果希望”永不过期”的数据不受影响 → 用 volatile-lru,永不过期的 key 不会被淘汰
– 如果希望热点数据更抗淘汰 → 用 LFU 系列,高频访问的 key 即使很少用也保留

淘汰触发的连锁反应

缓存穿透变多

淘汰意味着数据丢失,下次请求会穿透到数据库。如果淘汰量过大:

大量 key 被淘汰 → 大量缓存穿透 → 数据库压力飙升 → 接口响应变慢 → 更多请求堆积

应对:监控淘汰数量(evicted_keys),设置告警阈值。

热点数据被踢

LRU 是近似算法,在内存紧张时可能误淘汰即将被访问的数据:

# Redis 的近似 LRU
# 默认采样 5 个 key,淘汰其中最旧的
# 提高采样率可以更精确,但消耗更多 CPU
maxmemory-samples 10

调到 10 对大多数系统足够,调太高(20+)收益递减。

最佳实践

1. 预留缓冲空间

不要把 maxmemory 设到物理内存的上限。留出 20~30% 给系统、持久化、主从同步:

物理内存 8G → maxmemory 设 5~6G
物理内存 16G → maxmemory 设 10~12G

2. 设置合理的 TTL

即使有淘汰策略,设置 TTL 仍然是好习惯:

// 有 TTL 的数据会被优先考虑淘汰(volatile 类策略)
// 也能避免永远不用的数据占据内存
redis.opsForValue().set(key, value, 30, TimeUnit.MINUTES);

3. 监控淘汰情况

关键监控指标:

info stats → evicted_keys: 被淘汰的 key 数量
info memory → used_memory / maxmemory 使用比例

阈值建议
– 淘汰量 0 / 秒:健康
– 淘汰量 < 100 / 秒:内存偏紧,需要扩
– 淘汰量持续上升:紧急扩容

4. 冷热数据分离

将冷数据(很少访问的历史数据)迁移到更大的持久化存储,腾出内存给热数据。

面试要点

  • 默认 maxmemory-policy noeviction 会导致写入失败,生成环境一定要修改
  • allkeys-lru 是最通用的选择,适用于大部分场景
  • 不要只看淘汰策略,容量规划和监控同样重要
  • maxmemory 不是越大越好,要预留系统开销和突发流量
  • 能说出 evicted_keys 是判断内存是否够用的核心指标
© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容