bigywater.tech
Redis · 46

Stream 消息回收

消息被消费、被 ack 之后,Stream 里的内存什么时候还回去?很多人以为 XACK 或 XDEL 之后内存自然就少了。这篇用 10 万条消息量一量:ack、隔一条删一条、连续删除、XTRIM 各自能回收多少,以及为什么「删了一半」不等于「省了一半」。(「回收」在这里指内存回收;PEL 里消息的转移回收见第 44、45 篇。)

11.20 MB
全部 XACK 后的内存(写入时 11.20 MB);XLEN 仍是 100000
11.20 MB
隔一条 XDEL 一条(删一半)后的内存——几乎没变
5.60 MB
连续删前一半后的内存——约减半

XACK:只回收 PEL

实测 · 本机执行输出
阶段                        XLEN  radix-keys  MEMORY USAGE
写入完成                    100000        2778      11199430
读取但未 ack                100000        2778      20632009
全部 XACK                 100000        2778      11199657

读走不 ack 时,内存从 11.20 MB 涨到 20.63 MB;全部 ack 后回到 11.20 MB(比写入时多 227 字节)。XLEN、radix-tree-keys 都没变:ack 只是清理了 PEL,消息一条也没有被回收。

XDEL:取决于删得连不连续

实测 · 本机执行输出
删除方式                      XLEN  radix-keys  MEMORY USAGE
隔一条删一条                   50000        2778      11199353
连续删前一半                   50000        1390       5603776
(基线:同样写入 10 万条、什么都没删时 MEMORY USAGE = 11199430)

同样是删掉 5 万条:隔一条删一条,内存 11199353 字节,与基线(11199430)几乎相同,radix 节点数一个没少;连续删前一半,radix 节点数从 2778 降到 1390,内存降到 5603776。原因:一个节点里的消息只要还有一条没被删,这个节点(那段 listpack)就还在;被删的消息只是被打上标记。零星地 XDEL,几乎不省内存。(我只从节点数与内存的变化推断标记机制,没有拆 listpack 验证。)

XTRIM:按前缀整段裁掉

实测 · 本机执行输出
XTRIM t MINID 1790692921723-0 → 返回 50000;XLEN 50000,radix-keys 1390,MEMORY USAGE 5603073
XTRIM t MAXLEN 0 → 返回 50000;XLEN 0,radix-keys 0,MEMORY USAGE 260

XTRIM MINID 裁掉一半旧数据的结果(5603073 字节,1390 个节点)与「连续删前一半」相同;XTRIM MAXLEN 0 后 XLEN 0、radix 节点 0 个,MEMORY USAGE 只剩 260 字节。日志类的 Stream 通常应该靠 XTRIM 从头部裁剪,而不是零散 XDEL。

XDEL 只是打标记

实测 · 本机执行输出
                length = 50000
         entries-added = 100000
  max-deleted-entry-id = 1790692920996-736
           first-entry = 1790692921002-0

删除 5 万条之后:length 是 50000,entries-added 仍是 100000,max-deleted-entry-id 前进到被删的最大 ID。这些计数是 Stream 自己维护的,消费组的 lag 计算依赖它们。

分步演示:每种操作能回收多少内存

条形长度是 MEMORY USAGE
Stream 内存回收
本步的数据

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。10 万条消息,每条一个字段(值 100 字节),默认 stream-node-max-entries=100
    • 没有验证:XDEL 标记在 listpack 内的具体形式;Redis 内存分配器层面的碎片(MEMORY USAGE 是 Redis 计的逻辑占用,不等于进程 RSS);在有多个消费组 / 大 PEL 时 XTRIM 的行为(XTRIM 与 PEL、消费组的交互)
    京ICP备2026067502号-1京公网安备11010502063487号