给 Stream 限长有两种写法:MAXLEN 1000(精确)和 MAXLEN ~ 1000(近似)。文档说近似写法更高效。这篇把「更高效」量化,同时把「近似」的意思画出来:近似到底差多少,什么时候会多留,以及那个容易被忽略的 LIMIT。
MAXLEN 1000 XLEN = 1000 radix-keys = 10 MAXLEN ~ 1000 XLEN = 1000 radix-keys = 10 无裁剪 XLEN = 5000 radix-keys = 50
这一组恰好都落在 1000 条,因为总数 5000 是节点容量 100 的整数倍——看不出「近似」。要看清它,得逐条观察。
MAXLEN 1000 XLEN 最小 1000 最大 1000;每 20 次取样: [1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000] MAXLEN ~ 1000 XLEN 最小 1000 最大 1099;每 20 次取样: [1051, 1071, 1091, 1011, 1031, 1051, 1071, 1091, 1011, 1031, 1051, 1071, 1091, 1011, 1031]
先写满 5050 条,再逐条 XADD 300 次、每次读 XLEN。精确裁剪永远是 1000;近似裁剪在 1000–1099 之间锯齿:长度涨到 1099,再一次性掉 100 条(一个整节点),回到 1000 之后重新涨。近似裁剪不会少于你给的上限,只会多留至多一个节点。
node-max-entries XLEN 结果
10 1000
100 1000
500 1138节点容量 10 与 100 时 5000 条之后 XLEN 都是 1000(恰好对齐);节点容量调到 500 后,同样的写入得到 1138。这一列取决于写入总数与节点边界的相对位置,只说明「多留的量不会超过一个节点」,不是稳定的数值。(默认还有 4096 字节的节点上限,见第 39 篇。)
不裁剪 1.90 µs/条 (三次: 1.90, 1.88, 1.90) MAXLEN 1000 5.44 µs/条 (三次: 5.44, 5.46, 5.42) MAXLEN ~ 1000 2.76 µs/条 (三次: 2.77, 2.75, 2.76)
流已满 1000 条的稳态下,不裁剪 1.90 µs/条;近似裁剪 2.76 µs;精确裁剪 5.44 µs,是近似的 2.0 倍。精确裁剪每次 XADD 都要改动最老节点里的一条(把它标记删除),近似裁剪则是每 100 次才整体释放一个节点(这一层解释来自现象和第 46 篇对 XDEL 的观察,我没有另外抓取内部调用)。这是管道下每条的均摊值,不含网络往返。
XTRIM k MAXLEN 0 删除 1000000 条,命令耗时 2.9 ms XTRIM k MAXLEN ~ 0 删除 10000 条,命令耗时 0.1 ms XTRIM k MAXLEN ~ 0 LIMIT 1000 删除 1000 条,命令耗时 0.1 ms (XLEN 剩 999000) > XTRIM k MAXLEN 0 LIMIT 1000 (error) ERR syntax error, LIMIT cannot be used without the special ~ option
我原以为一次清空 100 万条会阻塞很久。实测 XTRIM MAXLEN 0 删除 100 万条只花了 0.0 ms:整个节点是整体释放的。MAXLEN ~ 0 只删了 10000 条——近似写法有个默认的 LIMIT,等于 100 × stream-node-max-entries;显式给 LIMIT 1000 只删 1000 条。LIMIT 必须和 ~ 同时使用,否则报语法错误。
实际后果:用 MAXLEN ~ 0 想清空一个大流,一次调用清不完,要么用精确的 MAXLEN 0,要么循环调用。