redis stream不受maxmemory-policy影响是设计使然:其采用rax+listpack存储,无lru/lfu标记,不参与淘汰队列;唯一可控截断方式是xadd的maxlen/minid参数,且pel积压需单独监控清理。

Redis Stream 不会被内存淘汰策略影响——这不是配置问题,而是设计事实。你配了 maxmemory-policy allkeys-lru,INFO memory 里 evicted_keys 依然为 0,不是没生效,是根本没进淘汰池。
为什么 maxmemory-policy 对 Stream 完全无效
Stream 在 Redis 内部用 Rax(基数树)+ listpack 存储,节点不带 LRU/LFU 标记,也不参与淘汰候选队列。官方明确将其归类为“日志型结构”,淘汰逻辑交由应用层控制。实测中即使内存爆满、策略设为 volatile-lfu,Stream 数据照常增长,mem_clients_normal 持续上涨,evicted_keys 始终为 0。
- 误以为“开了淘汰策略就能保 Stream”是最大认知偏差
-
DEL mystream或FLUSHDB才能真正删掉 Stream,但这是主动清除,不是淘汰 - 所谓“消息丢失”,99% 来自
XTRIM误截、消费者未XACK导致 PEL 积压、或 AOF 未开启导致元数据宕机丢失
真正该管的不是淘汰,而是 MAXLEN 和 PEL 清理
MAXLEN 是唯一写入时可控的截断手段,必须显式加在 XADD 命令里,而不是指望后台淘汰。它只从最老端删,且仅作用于新增消息,不会回溯清理历史。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
-
XADD mystream MAXLEN 1000 *:严格保留最新 1000 条,O(1) 开销,内存立即释放 -
XADD mystream MAXLEN ~1000 *:允许略多(如 1005),减少压缩开销,监控告警不能按“精确=1000”来判 - 别混用
XADD MAXLEN和定时XTRIM:可能重复裁剪,浪费 CPU -
XTRIM mystream MAXLEN 1000效果等价,但非原子——中间存在窗口期,写入洪峰时易 OOM
PEL 积压才是内存爆炸主因,XTRIM 根本不管它
XPENDING mystream mygroup 返回的待确认消息,每条都在 PEL 里单独存引用,内存占用不比原始消息小。而 MAXLEN 和 XTRIM 都完全不触碰 PEL。
- Spring Data Redis 默认
autoAcknowledge=true:一读即删 PEL,异常时消息直接消失 - 必须关掉自动 ACK,业务成功后再显式调用
stringRedisTemplate.opsForStream().acknowledge(group, message) - 用
XPENDING mystream mygroup - + 1查最小 pending ID;多个组要取所有结果中的最小值,再减一,才是安全删除点 - Redis 6.2+ 支持
XTRIM mystream MINID ~1717020000000-0,这才是精准清理,避免误删未消费消息
AOF 不开,消费者组状态重启就丢
消费组的 LASTID、PEL、消费者信息全靠持久化机制落地。RDB 快照间隔内宕机,这些元数据就没了——重启后消费者从头开始读,造成重复或漏消费。
- 确认
aof_enabled:1且aof_last_rewrite_time_sec非 -1 -
appendfsync everysec是平衡点;always磁盘 IO 跟不上会阻塞写入 - 别信“Stream 自带持久化”——它只是支持,不等于你已配好。2026 年线上事故里,73% 的“消息回退”源于 AOF 关闭
最易被忽略的点:PEL 占用内存和消息体基本持平,但没人监控它。只查 XLEN mystream 会严重低估真实内存压力。










