一、Redis 内存淘汰策略
当 Redis 内存达到 maxmemory
限制时,需通过淘汰策略释放空间。Redis 提供 8 种淘汰策略,分为以下三类:
1. 不淘汰策略
- noeviction(默认):内存不足时拒绝新写入,返回错误(如
OOM
)。
适用场景:数据不可丢失,需严格保证一致性。
2. 淘汰有过期时间的键
- volatile-lru:在设置过期时间的键中,淘汰最近最少使用的键(LRU)。
- volatile-ttl:淘汰剩余生存时间(TTL)最短的键。
- volatile-random:随机淘汰有过期时间的键。
- volatile-lfu(Redis 4.0+):淘汰使用频率最低的键(LFU)。
适用场景:优先清理即将过期或低频访问的数据。
3. 淘汰所有键
- allkeys-lru:从所有键中淘汰最近最少使用的键。
- allkeys-random:随机淘汰任意键。
- allkeys-lfu(Redis 4.0+):淘汰使用频率最低的键。
适用场景:所有数据均可被淘汰,需保留热点数据。
策略选择建议
- 高频访问场景:优先使用
allkeys-lru
或allkeys-lfu
,保留最近活跃数据。 - 低频或随机场景:使用
random
策略快速释放内存。 - 版本依赖:Redis ≥4.0 时,
lfu
策略更精准。
二、数据库与缓存一致性
缓存更新时,需确保数据库和 Redis 数据的一致性。常见策略及问题如下:
1. 更新策略对比
- 更新缓存:
- 优点:高缓存命中率,减少回源查询。
- 缺点:频繁更新导致无效操作(如数据未被读取);线程安全问题(多线程更新冲突)。
- 删除缓存:
- 优点:避免无效更新,仅需一次缓存重建。
- 缺点:可能引发缓存穿透或短暂不一致(旧数据回填)。
2. 操作顺序问题
- 先删缓存后更新数据库:
- 风险:删除缓存后,其他线程可能从数据库读取旧数据并回填。
- 解决方案:异步更新缓存(如通过消息队列),但无法保证强一致性。
- 先更新数据库后删除缓存:
- 风险:缓存未删除时,其他线程可能读取旧数据。
- 解决方案:
- 延时双删:删除缓存后,延迟一段时间再次删除(如 50ms),确保旧数据未写入。
- 分布式锁:在删除缓存时加锁,避免并发冲突。
3. 推荐实践
- 延迟双删:结合异步队列实现,减少性能损耗。
- MQ 异步更新:通过消息队列解耦更新操作,保证最终一致性。
- 逻辑过期:在缓存中存储数据版本号,读取时校验版本,避免脏数据。
三、总结
淘汰策略:根据数据访问模式选择 LRU
或 LFU
,优先保留热点数据。
- 一致性:推荐 先更新数据库后删除缓存,结合 延时双删 或 分布式锁 降低风险。
- 扩展方案:结合布隆过滤器解决缓存穿透,热点数据设置长 TTL 避免击穿。
通过合理选择策略和优化流程,可显著提升系统性能与数据可靠性。