在一个 Redis 值里紧凑地存下海量是/否标记的方式。

Redis 位图用位而不是存储数字

Redis 位图是把字符串按单个位解释的用法,并不是一种独立的键类型。它适合稠密的是非标记,例如按用户记录每日活跃状态。一千万个连续标志需要一百二十五万个载荷字节,但这个估算不包括键名、对象元数据、分配器额外开销,也不包括业务标识到位偏移的映射,不能直接当成实例总内存。 先定义偏移的契约 SETBIT 在从零开始的偏移处写入零或一,并返回写入前的位值。已经为一的位置再次写一,不会增加成员数量。偏移零对应第一个字节的最高位,偏移八才进入第二个字节。对同一个键执行 GET,读到的是底层字节,它们未必是有效文本,所以二进制数据不应默认按 UTF-8 解码。 GETBIT 对缺失键或超出现有字符串长度的位置返回零,而且不会因为读取就扩容。因此,零不能区分“明确不活跃”与“尚未记录”,需要先决定业务是否允许合并这两种状态。SETBIT 与 GETBIT 要求键的值是字符串;如果键实际是哈希,会报类型错误,不会自动把哈希字段转换成位。BITOP 则会在目标键写入新的字符串。 内存取决于写入过的最高偏移,而不是当前有多少个位为一。写偏移 n 至少需要 floor(n / 8) + 1 个载荷字节,即使要写入的是零也一样。后来把高位清零,并不会缩短字符串。稀疏外部编号因此可能用极少的有效标记触发巨大分配。应验证允许的偏移范围,并采用稳定且足够稠密的编号映射,而不是直接信任任意业务 ID。 计数和组合都要明确范围 BITCOUNT 默认检查全部字节。可选的 start 和 end 是包含两端的字节位置;从 Redis 7.0 开始,可以用 BIT 修饰符把它们改为位位置。切换单位只改变查询区间,不会改变键里实际存储的表示。返回值是为一的位数,不是最大的成员编号,也不是位图所能容纳的全部用户数。 BITOP OR 计算成员并集,AND 计算交集。较短的输入和不存在的键,会被视为补零到最长输入的长度。目标键会被新字符串覆盖,原本附在目标键上的过期时间也会移除。因此,派生结果需要明确的寿命策略,不能以为之前给结果键设置过一次期限,以后的重算就会自动继承。 坏掉的样子 BITCOUNT、BITPOS 和 BITOP 都可能遍历大量数据。底层位运算即使经过优化,也不代表全量计算是常数时间;把字符串扩展到远端偏移,还需要分配中间的空间。评估时要同时看偏移跨度、查询频率、派生结果保留多久以及峰值分配。活跃用户很少,并不能证明稀疏位图占用的资源很少。 ...

四月 29, 2027 · 3 分钟 · XB Field Notes