Redis无通用“防逐出”策略,本质是通过TTL设置、实例隔离等手段将关键数据物理隔离于淘汰池外;volatile-策略仅作用于带过期时间的key,allkeys-则无差别淘汰,noeviction仅拒绝写入而非保护数据。

必须先明确:没有“防逐出”的通用策略,只有“按业务语义控制逐出范围”的配置逻辑。 Redis 不会区分“重要”或“不重要”,它只认 maxmemory 和 maxmemory-policy 的规则。所谓“防误删”,本质是把不该参与淘汰的数据,从淘汰候选池里物理隔离出去。
volatile-* 策略只对带过期时间的 key 生效
如果你有一批关键数据(比如用户登录态、订单状态快照)必须长期驻留,又不想被 allkeys-lru 误杀,就别给它们设 TTL —— 这是最硬的隔离手段。Redis 的 volatile-lru、volatile-ttl 等策略压根不会扫描没设置过期时间的 key,它们天然免疫。
- 设置了
EXPIRE或SETEX的 key 才进 volatile 类策略的候选池 -
SET写入且未调用EXPIRE的 key,永远不在volatile-*范围内 - 注意:使用
PERSIST可以临时移除已设的过期时间,让 key “退出” volatile 池
allkeys-* 策略下,所有 key 都在淘汰射程内
选 allkeys-lru 或 allkeys-lfu 时,Redis 不管你是不是核心业务数据,只要内存满,就会按算法挑 key 删。这时候“防逐出”只能靠外部设计:
- 把真正不能丢的数据,存到另一个独立 Redis 实例(配
noeviction),和缓存实例物理隔离 - 避免在同一个实例混存“永久态”和“临时缓存”,否则再精细的策略也救不了语义冲突
-
allkeys-lfu比allkeys-lru更抗突发访问扰动,但对冷数据更狠——如果某些关键 key 访问稀疏但不可丢,LFU 反而更危险
noeviction 不是“防逐出”,是“拒绝写入”
很多人以为 noeviction 能保数据,其实它只是把问题甩给上层:OOM command not allowed when used memory > 'maxmemory' 错误会直接打到业务代码。它不删数据,但也不让新数据进来。
- 适合场景极窄:比如配置中心只读下发、离线任务中间结果暂存,且业务能容忍写失败
- 绝对不适合在线交易类系统——订单创建失败比缓存丢失后果严重得多
- 线上启用前必须确认:你的客户端有重试+降级逻辑,否则就是主动制造雪崩点
maxmemory-samples 影响淘汰精度,不是越大越好
maxmemory-samples 控制每次淘汰时随机采样的 key 数量,默认是 5。调高它能让 LRU/LFU 更接近理论效果,但代价是 CPU 开销上升,尤其在大 key 多的实例上。
- 从 5 改成 10,LRU 准确率提升有限,但
INFO stats里的evicted_keys增速可能变慢(因为采样更准,一次命中率更高) - 超过 20 后收益急剧下降,反而增加主线程延迟,线上不建议盲目调高
- 真正影响“是否误删”的,从来不是采样数,而是你一开始有没有把 key 分到正确的策略池里
最常被忽略的一点:Redis 的淘汰动作发生在命令执行前,它不感知业务上下文。所谓“重要数据”,必须由你在写入时就通过 TTL 设置、实例拆分、命名空间约定等方式打上标记,而不是指望策略自动识别——它没有这个能力。











