noeviction最安全,因LRU类策略会误删未消费消息或元数据,导致消息丢失、Stream重放错乱;volatile-lru依赖TTL难预估,allkeys-lru无差别淘汰更危险;应靠maxmemory+监控+主动清理保障可靠性。

消息队列场景下,noeviction 是最安全、最推荐的策略,其他淘汰策略都可能造成消息丢失或语义错乱。
为什么 volatile-lru / allkeys-lru 在 MQ 场景里很危险
消息队列的核心契约是“至少一次投递”或“有序不丢”,而 LRU 类策略会无差别淘汰 key——哪怕那个 key 是一个未被消费的待处理消息(比如用 LPUSH + BRPOP 模拟的队列,或用 Stream 存储的 pending entry)。一旦 Redis 因内存压力淘汰了某个消息 key,它就彻底消失了,消费者再也收不到。
-
volatile-lru要求你给每个消息 key 显式设 TTL,但实际中很难预估消费延迟;TTL 设短了丢消息,设长了又起不到内存保护作用 -
allkeys-lru更不可控:连元数据 key(如消费者组 offset、ack 记录)都可能被误删,导致 Stream 重放错乱或 group 状态崩溃 - Redis 的近似 LRU 采样机制(默认只看
maxmemory-samples个 key)会让淘汰行为更难预测,线上压测时可能完全复现不出问题,上线后才爆发
volatile-ttl 看似合理,但实际不适用于可靠队列
这个策略常被误认为“适合有生命周期的消息”,但它只看剩余 TTL,不区分消息状态。问题在于:
- 你无法保证“即将过期”的就是可丢弃的消息——比如一个延迟 5 分钟的定时任务消息,TTL 剩 10 秒时被删,业务就漏执行
- Stream 消息本身不支持 per-message TTL,必须靠外部 key(如
msg:123)模拟,管理成本高且易出错 - 当大量消息 TTL 集中在相近时间点(例如批量定时任务触发),
volatile-ttl会在同一时刻集中淘汰,引发抖动甚至雪崩
真正该做的:用 maxmemory + noeviction 倒逼容量治理
消息队列不是缓存,它的数据是业务流程的中间状态,必须可追溯、可重放。与其依赖淘汰策略“保命”,不如让内存上限成为容量水位警戒线:
- 配置
maxmemory为物理内存的 70%~80%,并配合监控告警(如used_memory_peak_perc> 90%) - 用
noeviction策略,让写入失败成为明确信号:当ERR OOM command not allowed when used memory > 'maxmemory'出现,说明队列积压已超承载能力,必须触发降级(如限流、落盘、告警人工介入) - 对 Stream,定期用
XTRIM或XDEL主动清理已确认消息;对 list 队列,用LTRIM控制长度——这些才是可控、可审计的清理方式
最容易被忽略的一点:从库不执行淘汰策略,但主库淘汰后会同步 DEL 命令。如果你误配了 volatile-lru,主库删了消息,从库也跟着删,故障恢复时切从库变主库,消息就永久丢失了——这种链路级风险,在 MQ 场景下比性能下降严重得多。











