
📌 为什么需要缓存淘汰机制?
Redis作为内存数据库,所有数据都存储在宝贵的内存中。但内存空间是有限的,当内存使用达到maxmemory限制时,Redis必须做出艰难抉择:哪些数据该保留?哪些数据该淘汰?
# redis.conf 关键配置
maxmemory 2gb # 最大内存限制
maxmemory-policy allkeys-lru # 淘汰策略
🔍 Redis支持的6种淘汰策略
Redis提供了6种不同的淘汰策略,我们可以根据业务特点选择最适合的方案:
| 策略 | 作用范围 | 底层算法 | 适用场景 |
|---|---|---|---|
noeviction | 不淘汰 | 无 | 关键数据不能丢失 |
allkeys-lru | 所有key | LRU算法 | 热点数据访问 |
volatile-lru | 带过期时间的key | LRU算法 | 混合数据 |
allkeys-random | 所有key | 随机选择 | 无明确规律 |
volatile-random | 带过期时间的key | 随机选择 | 临时数据 |
volatile-ttl | 带过期时间的key | TTL比较 | 短期缓存 |
💡 关键区别:
allkeys-针对所有key,volatile-仅针对设置了过期时间的key
🧠 深入核心淘汰算法原理
1. LRU(最近最少使用)算法
经典LRU实现:使用双向链表+哈希表
-
新访问的数据移到链表头部
-
淘汰时从链表尾部删除
Redis的近似LRU优化:
-
出于性能考虑,Redis采用抽样淘汰而非精确LRU
-
每次随机选取5个key(可配置),淘汰其中最久未使用的
-
通过
maxmemory-samples参数控制抽样数量
// Redis近似LRU实现核心逻辑(简化版)
key = random_sample(keys)
min_timestamp = current_time
candidate = null
for each key in samples:
if key.last_used < min_timestamp:
min_timestamp = key.last_used
candidate = key
evict(candidate)
2. LFU(最不经常使用)算法(Redis 4.0+)
LFU核心思想:
-
统计每个key的访问频率
-
淘汰访问次数最少的key
Redis的LFU实现特点:
-
使用Morris计数器节省空间
-
访问计数会随时间衰减(避免历史数据长期占据内存)
-
通过
lfu-log-factor和lfu-decay-time控制衰减速度
# LFU相关配置
lfu-log-factor 10 # 计数器增长对数因子
lfu-decay-time 1 # 计数器衰减时间(分钟)
3. TTL(生存时间)优先策略
-
只淘汰设置了过期时间的key
-
优先淘汰剩余生存时间(TTL)最短的key
-
实现方式:Redis维护一个最小堆数据结构
4. 随机淘汰策略
-
完全随机选择key进行淘汰
-
实现简单,但可能淘汰热点数据
-
适用于数据访问完全随机的场景
⚙ Redis淘汰机制底层实现
Redis淘汰机制的核心代码在evict.c文件中,主要流程:
-
内存检查:每次处理命令前检查内存使用
-
淘汰触发:达到maxmemory时触发淘汰流程
-
策略执行:根据配置的策略执行淘汰
-
内存释放:删除选中key并释放内存
// 内存检查核心逻辑(简化)
int processCommand(client *c) {
if (server.maxmemory && !server.lua_timedout) {
int out_of_memory = freeMemoryIfNeeded() == C_ERR;
if (out_of_memory && reject_cmd_on_oom) {
rejectCommand(c, shared.oomerr);
return C_OK;
}
}
// ...执行命令
}
🚀 不同策略性能对比
| 策略 | 时间复杂度 | 内存开销 | 精确度 |
|---|---|---|---|
| 精确LRU | O(1) | 高 | 100% |
| Redis近似LRU | O(N)采样 | 低 | 可配置 |
| LFU | O(1) | 中等 | 较高 |
| TTL | O(logN) | 中等 | 100% |
| 随机 | O(1) | 无 | 无 |
💡 最佳实践建议
-
热点数据场景:优先使用
allkeys-lru -
长期缓存+临时数据混合:使用
volatile-lru -
突发流量防护:LFU能更好应对流量变化
-
内存敏感环境:适当降低
maxmemory-samples提高性能 -
监控关键指标:
redis-cli info memory # 关注evicted_keys,used_memory,maxmemory
📚 进阶思考题
-
为什么Redis不采用真正的LRU实现?
-
LFU的Morris计数器是如何工作的?
-
如何基于业务特点设计自定义淘汰策略?
欢迎在评论区分享你的见解!如果觉得有帮助,请点赞收藏支持~
🔗 扩展阅读:Redis源码evict.c、redis.conf官方文档
7149

被折叠的 条评论
为什么被折叠?



