Redis 的内存淘汰策略是如何工作的?
Redis
内存管理
淘汰策略
性能优化
什么是内存淘汰策略?
Redis 内存淘汰策略是当内存使用达到上限时,自动移除部分数据以维持服务可用的机制。就像图书馆书架满了之后,需要根据规则下架部分书籍来放入新书。
核心作用
- 防止内存溢出:通过
maxmemory
配置阈值(默认不限制) - 维持写入能力:避免进入只读的 noeviction 状态
- 智能数据筛选:根据访问模式保留最有价值的数据
8 种淘汰策略解析
策略对照表(生产环境选型参考)
策略名称 | 作用范围 | 算法特点 | 适用场景 | 版本要求 |
---|---|---|---|---|
noeviction | 不淘汰 | 拒绝写入 | 数据不可丢失场景 | 2.0+ |
allkeys-lru | 所有键 | 近似 LRU 算法 | 通用缓存场景(推荐) | 2.8+ |
volatile-lru | 过期键 | 近似 LRU | 混合持久化缓存 | 2.8+ |
allkeys-random | 所有键 | 随机淘汰 | 均匀访问模式 | 2.0+ |
volatile-random | 过期键 | 随机淘汰 | 临时数据存储 | 2.0+ |
volatile-ttl | 过期键 | 剩余时间排序 | 时效性数据 | 2.0+ |
allkeys-lfu | 所有键 | 近似 LFU | 热点数据场景 | 4.0+ |
volatile-lfu | 过期键 | 近似 LFU | 热点临时数据 | 4.0+ |
核心算法实现原理
1. 近似 LRU 算法
面试重点:理解 Redis 如何通过概率采样实现高效 LRU
// Redis 源码片段(evict.c)
#define EVICTION_SAMPLES_ARRAY_SIZE 16
unsigned long estimateObjectIdleTime(robj *o) {
return LRU_CLOCK() - o->lru;
}
void evictionPoolPopulate(dict *sampledict, struct evictionPoolEntry *pool) {
// 随机采样 5 个键放入候选池
for (int i = 0; i < EVICTION_SAMPLES_ARRAY_SIZE; i++) {
// 选择具有最大空闲时间的键
if (bestkey->lru > pool[EVPOOL_SIZE-1].idle) {
evictionPoolPopulateItem(pool, bestkey);
}
}
}
算法优化点:
- 默认采样数量 5(可配置)
- 使用固定大小候选池(16 个条目)
- 每次淘汰选择候选池中最久未使用的键
补充说明:
- Redis 利用全局 LRU 时钟和概率采样相结合,避免全量扫描所有键,从而降低淘汰操作的时间复杂度。
- 在面试中,重点在于理解候选池机制及其对缓存性能的优化作用。
2. 近似 LFU 算法
实现机制:
- 使用 Morris 计数器概率衰减
- 访问频率对数化存储(0-255)
- 衰减因子配置(lfu-decay-time)
# 查看键的 LFU 信息
redis-cli object freq key1
补充说明:
- Morris 计数器采用对数增长策略,有效防止频繁访问时计数值过快增长,同时降低内存消耗。
- 面试常关注 LFU 算法如何更灵敏地捕捉热点数据,与传统计数器方式的区别是讨论重点。
内存碎片整理
触发条件及配置:
# 启用主动碎片整理
activedefrag yes
# 配置忽略小碎片区域(低于指定字节,避免不必要的整理)
active-defrag-ignore-bytes 100mb
# 当 used_memory_rss 与实际 used_memory 差异较大(碎片率超过阈值)时触发整理
active-defrag-threshold-lower 10
整理过程: Redis 内存碎片整理机制通过主动干预内存分配器中分散的数据块,实现内存紧凑化,具体步骤如下:
- 碎片检测:定期扫描内存,评估 used_memory_rss 与实际 used_memory 的比例,判断是否存在严重碎片问题。
- 候选区域选择:从内存中识别出高碎片率区域,作为数据重排的候选区域。
- 数据重排:将候选区域中的有效数据复制到连续的新内存空间中,以减少内存分散,并优化后续内存分配。
- 内存回收:逐步释放旧的、已碎片化的内存块,使得内存资源得以有效复用。
- 渐进整理:整个整理过程采用渐进式方式,分步执行,避免一次性大规模操作引起系统阻塞,保证前台请求的响应不会受到影响。
生产环境配置方案
电商秒杀场景配置示例
# 内存限制(设置为物理内存的 3/4)
maxmemory 12gb
# 使用 LFU 策略保留热点商品数据
maxmemory-policy allkeys-lfu
# 调整 LFU 衰减周期(1 小时)
lfu-log-factor 10
lfu-decay-time 3600
# 启用主动碎片整理
activedefrag yes
监控指标体系
# 内存关键指标
redis-cli info memory | grep -E "used_memory|maxmemory|mem_fragmentation_ratio"
# 淘汰统计
redis-cli info stats | grep evicted_keys
# 碎片整理状态
redis-cli info memory | grep defrag
常见问题排查
1. 内存未释放问题
现象:达到 maxmemory 但淘汰策略未生效
处理步骤:
# 确认策略不是 noeviction
CONFIG GET maxmemory-policy
# 检查键的过期时间(返回-1表示未设置过期时间)
TTL mykey
# 分析内存分布
redis-cli --bigkeys
2. LFU 策略热点失效
现象:高频访问数据被意外淘汰
处理步骤:
# 提高计数器精度(值越小精度越高)
lfu-log-factor 10
# 加快频率衰减速度(单位:分钟)
lfu-decay-time 1800
3. 内存碎片过高问题
现象:内存使用率低但无法写入新数据
处理步骤:
# 紧急情况手动整理
redis-cli memory purge
# 动态调整整理强度
CONFIG SET active-defrag-cycle-min 5
CONFIG SET active-defrag-cycle-max 10
性能调优建议
- 容量规划:保持内存使用率 ≤70%
- 键值设计:避免大对象(超过 1MB)
- 版本升级:4.0+ 版本支持更精细策略
- 混合存储:冷数据持久化到磁盘
相关推荐: