缓存相关,redis
Redis 内存淘汰策略
Redis 内存淘汰策略是指当 Redis 的内存使用达到上限时,如何决定清理哪些数据以保证新数据的存入。Redis 提供了多种内存淘汰策略,每种策略适用于不同的场景和需求。
模拟面试:Redis 淘汰策略的拷打
以下是一个模拟的面试场景,面试官逐步深入提问,答案详细且结构化,涵盖技术细节和实际应用。
面试官:Redis 的内存淘汰策略有哪些?分别适用于什么场景?
候选人:
Redis 提供了八种淘汰策略,分为两类:针对所有键(allkeys)和仅针对设置了过期时间的键(volatile)。具体如下:
- noeviction:不淘汰,内存满时拒绝写入,适合数据不可丢失的场景,如金融数据存储。
- allkeys-lru:对所有键使用 LRU 算法,适合热点数据频繁访问的缓存系统。
- allkeys-lfu:对所有键使用 LFU 算法,适合访问频率差异大的场景,如推荐系统。
- allkeys-random:随机淘汰所有键,适合无明显访问模式的测试环境。
- volatile-lru:对设置了 TTL 的键使用 LRU,适合混合数据场景,如临时缓存。
- volatile-lfu:对设置了 TTL 的键使用 LFU,适合关注频率的临时数据。
- volatile-random:随机淘汰设置了 TTL 的键,适合简单临时数据场景。
- volatile-ttl:优先淘汰 TTL 最短的键,适合短生命周期数据。
这些策略通过 maxmemory-policy 配置,默认是 noeviction。
面试官:LRU 和 LFU 的区别是什么?Redis 是如何实现 LRU 的?
候选人:
- LRU(Least Recently Used) :根据最近访问时间淘汰,优先删除最久未访问的键。适合热点数据场景。
- LFU(Least Frequently Used) :根据访问频率淘汰,优先删除访问次数最少的键。适合长期运行、频率差异大的场景。
Redis 的 LRU 实现:
Redis 并未实现严格的 LRU,而是采用近似 LRU算法,具体步骤:
- 采样:从键空间中随机抽取一小部分键(默认 5 个,可通过
maxmemory-samples配置)。 - 时间戳记录:每个键维护一个访问时间戳(基于
LRU_CLOCK)。 - 比较淘汰:比较采样键的访问时间,淘汰最旧的键。
- 优化:Redis 使用一个全局 LRU 时钟(精度为 1 秒),减少维护开销。
这种近似 LRU 算法在性能和精度间取得平衡,采样越多,精度越高,但开销也越大。
面试官:Fast 模式和 Slow 模式是什么?它们会影响淘汰效果吗?
候选人:
Fast 模式和 Slow 模式不是淘汰策略,而是 Redis 执行淘汰算法时的运行模式,影响淘汰的效率和精度:
- Fast 模式:采样少量数据,快速执行,适合高并发场景,但精度较低。
- Slow 模式:采样更多数据,执行更精确的算法(如完整的 LRU/LFU 计算),适合数据价值高的场景。
影响:
- Fast 模式可能导致次优淘汰(误删高价值数据),但响应快。
- Slow 模式淘汰更精准,但性能开销大。
- 通过
maxmemory-eviction-tenacity(0 到 100)控制,0 为纯 Fast,100 为纯 Slow,中间值动态调整。
实际应用:
- 高并发场景(如电商秒杀)用 Fast 模式。
- 高精度场景(如推荐系统缓存)用 Slow 模式。
面试官:如果我要实现一个自定义淘汰策略,应该怎么做?
候选人:
Redis 本身不支持直接自定义淘汰策略,但可以通过以下方式实现:
-
修改源码:
- Redis 是开源的,可以修改
evict.c中的淘汰逻辑,添加自定义算法。 - 例如,基于键的大小、业务优先级等设计新策略。
- 缺点:需要重新编译,维护成本高。
- Redis 是开源的,可以修改
-
外部控制:
- 使用 Redis 的
INFO命令监控内存使用情况。 - 通过客户端脚本定期扫描键空间,结合业务逻辑(如优先级、访问频率)执行
DEL命令删除键。 - 优点:无需改源码,灵活性高。
- 缺点:需要额外开发,可能影响性能。
- 使用 Redis 的
-
结合 Lua 脚本:
- 使用 Redis 的 Lua 脚本实现简单的淘汰逻辑,通过
EVAL命令定期运行。 - 例如,扫描特定模式的键,基于自定义规则删除。
- 局限性:复杂逻辑可能受 Lua 脚本性能限制。
- 使用 Redis 的 Lua 脚本实现简单的淘汰逻辑,通过
推荐方案:
- 小规模场景:使用外部控制 + Lua 脚本。
- 大规模场景:修改源码并充分测试。
面试官:实际生产环境中,你会如何选择淘汰策略?
候选人:
选择淘汰策略需要综合考虑业务场景、数据特性和服务要求:
-
明确数据特性:
- 数据是否有明确的生命周期?如果有,优先考虑 volatile-* 策略。
- 数据访问是否有热点?如果有,LRU 或 LFU 更适合。
-
评估业务需求:
- 数据丢失是否可接受?如果不可接受,选择
noeviction。 - 性能敏感度高?选择 Fast 模式或
allkeys-random。
- 数据丢失是否可接受?如果不可接受,选择
-
典型场景:
- 电商缓存:热点数据多,选
allkeys-lru+ Fast 模式。 - 推荐系统:频率差异大,选
allkeys-lfu+ Slow 模式。 - 临时数据:有 TTL,选
volatile-ttl或volatile-lru。
- 电商缓存:热点数据多,选
-
监控与调优:
- 使用
INFO MEMORY监控evicted_keys和mem_used。 - 调整
maxmemory-samples和maxmemory-eviction-tenacity优化淘汰效果。
- 使用
我的经验:
在某电商项目中,我们使用 allkeys-lru 结合 Fast 模式,配合 maxmemory-samples=10,在高并发场景下保持了低延迟,同时通过监控调整 maxmemory 避免频繁淘汰。
作者:Asthenian
链接:https://juejin.cn/post/7503454000494280742
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
