1. 为什么我们需要缓存淘汰策略?

想象咱们的Redis缓存就像小区里的公共储物柜。当所有柜子都被占满时,新来的快递包裹该放在哪?这时候就需要一套明确的规则来决定哪些包裹可以扔掉(淘汰),哪些需要保留。Redis的缓存淘汰策略就是解决这个问题的核心机制。

2. Redis支持的八种淘汰策略

(以下示例均基于Redis 6.2版本)

2.1 不淘汰系列

# 配置文件redis.conf
maxmemory 2gb          # 设置最大内存为2GB
maxmemory-policy noeviction  # 拒绝所有写入请求

适合场景:金融交易日志等绝对不能丢失的数据存储

2.2 随机淘汰系列

# 命令行动态配置
127.0.0.1:6379> CONFIG SET maxmemory 1gb
127.0.0.1:6379> CONFIG SET maxmemory-policy allkeys-random

适合场景:商品图片缓存这种价值均等的存储需求

2.3 LRU系列(最近最少使用)

# Python连接示例(需安装redis-py)
import redis

r = redis.Redis()
r.config_set('maxmemory', '500mb')
r.config_set('maxmemory-policy', 'allkeys-lru')  # 全局LRU淘汰

# 模拟数据访问
r.set('user:1001', '张三资料', ex=3600)  # 设置1小时过期
r.get('user:1001')  # 访问数据会刷新LRU时钟

适合场景:社交媒体用户资料缓存

2.4 LFU系列(最不经常使用)

// Java示例(使用Jedis库)
Jedis jedis = new Jedis("localhost");
jedis.configSet("maxmemory", "2gb");
jedis.configSet("maxmemory-policy", "volatile-lfu");  // 带过期时间的LFU

// 设置不同访问频率的键
jedis.setex("news:top1", 86400, "今日头条");  // 24小时过期
IntStream.range(0,100).forEach(i->jedis.get("news:top1"));  // 高频访问

适合场景:新闻热点排行榜

2.5 TTL优先策略

# 使用redis-cli测试
127.0.0.1:6379> CONFIG SET maxmemory-policy volatile-ttl
127.0.0.1:6379> SET promo1 "双11活动" EX 3600  # 1小时后过期
127.0.0.1:6379> SET promo2 "黑五特惠" EX 1800  # 半小时后过期
# 当内存不足时,promo2会优先被淘汰

3. 配置实战:电商平台案例

假设我们运营一个日均UV百万的电商平台,缓存架构如下:

# 缓存层级配置方案
商品详情缓存:
  maxmemory: 4gb
  policy: allkeys-lfu
  timeout: 7200秒

购物车缓存:
  maxmemory: 2gb
  policy: volatile-lru
  timeout: 259200秒  # 3天有效期

促销活动缓存:
  maxmemory: 1gb
  policy: volatile-ttl
  timeout: 根据活动时间动态设置

配置后效果对比:

# 配置前内存使用
used_memory_human:4.00G
evicted_keys:0

# 配置后运行一周
used_memory_human:3.92G
evicted_keys_per_sec:15.3  # 健康的内存循环

4. 深度技术解析

4.1 LRU的近似算法

Redis采用的并非传统LRU,而是通过随机采样实现的近似LRU。这就像考场监考老师不会盯着每个学生,而是通过随机抽查来维持秩序:

// Redis源码片段(evict.c)
unsigned long long estimateObjectIdleTime(robj *o) {
    return mstime() - o->lru * LRU_CLOCK_RESOLUTION;
}

这种设计使得Redis在处理百万级键时,仍能保持O(1)时间复杂度。

4.2 LFU的频次统计

LFU的频次统计不是简单计数器,而是采用概率衰减算法:

# 伪代码解释衰减机制
def update_lfu_counter(key):
    # 每次访问时
    counter = get_current_counter(key)
    counter = counter * decay_factor + base_increment
    save_counter(key, counter)

这种设计防止长期不访问的历史热点数据占用内存。

5. 策略选型指南

5.1 电商场景

  • 秒杀系统:volatile-ttl + 精确过期时间
  • 商品推荐:allkeys-lfu
  • 订单数据:noeviction + 持久化备份

5.2 社交平台

  • 用户关系:allkeys-lru
  • 热点话题:volatile-lfu + 动态TTL
  • 聊天记录:volatile-ttl + 消息队列备份

6. 避坑指南:血泪教训总结

  1. 冷启动陷阱:新系统上线时缓存命中率为0,建议预热加载
# 使用redis-cli批量预热
cat product_ids.txt | xargs -I{} redis-cli get product:{}
  1. 内存计算误差:实际内存占用会比配置值多5-10%
# 安全配置公式
maxmemory = 物理内存 * 0.75 - 500MB
  1. 混合持久化风险:当同时开启AOF重写和淘汰策略时,可能触发OOM
# 监控命令
redis-cli info memory | grep "maxmemory"

7. 关联技术:持久化机制

淘汰策略与持久化的关系就像冰箱的冷藏室和冷冻室:

# 当启用RDB持久化时
save 900 1       # 15分钟有1次修改就保存
save 300 10      # 5分钟有10次修改

# AOF持久化配置
appendfsync everysec  # 折衷方案

8. 性能优化参数

# 高级配置项(redis.conf)
lfu-log-factor 10   # LFU对数因子
lfu-decay-time 1    # 衰减周期(分钟)
active-defrag yes   # 启用内存碎片整理

9. 终极选择指南

通过决策树帮助选择策略:

是否允许数据丢失?
├─ 否 → noeviction
└─ 是 → 数据是否带过期时间?
   ├─ 是 → 需要精准淘汰?
   │   ├─ 是 → volatile-lfu
   │   └─ 否 → volatile-ttl
   └─ 否 → 访问模式?
       ├─ 均匀访问 → allkeys-random
       ├─ 近期热点 → allkeys-lru
       └─ 长期热点 → allkeys-lfu

10. 总结与展望

通过合理配置Redis淘汰策略,某视频平台将缓存命中率从68%提升到92%,年节省服务器成本约300万元。记住:没有最好的策略,只有最适合业务场景的策略。随着Redis 7.0引入的TinyLFU算法,未来我们可能会有更精细的淘汰控制能力。建议每季度根据业务变化重新评估策略配置,就像给缓存系统做"健康体检"一样重要。