Bitmap 很容易给人一种「按位存储,所以一定省内存」的感觉。这个判断只说对了一半:当 offset 连续且密集时它很省;当 offset 稀疏且巨大时,它会直接按最大 offset 扩容。

SETBIT key 100000000 1 不会只存一个 1,而是要让底层 String 扩到能覆盖这个位置。Redis 还会把中间字节清零,这就是某些线上事故里一条命令吃掉十几 MB 的原因。

先把机制边界说清楚

这一篇讨论 Bitmap 和 Bitfield 的内存模型,不讨论所有统计系统。Bitmap 适合布尔标记和密集 ID,不适合把雪花 ID、手机号这类大跨度值直接当 offset。

整体路径

Bitmap 是 String 的位视图

上面这张图先把主线铺开:最大 offset 决定 SDS 至少要扩到哪里。读 Redis 这类系统,最重要的是别只停在命令接口,要继续追问它在内存里是什么形状、在主线程上走多远、失败时会留下什么状态。

底层机制

  • Bitmap 没有独立底层类型,所有位都落在 String 的 SDS 字节数组里。
  • offset 会换算成字节位置,超过当前长度时触发扩容并填零。
  • BITCOUNTBITOP 会按字节范围扫描,范围越大,CPU 成本越高。
  • Bitfield 在同一个 String 上维护多个定长计数器,原子性好,但溢出策略要提前设计。

这些机制放在一起看,就能把「这个命令能不能用」改成「这个命令在当前数据规模下还便不便宜」。Redis 的很多坑,不是命令本身错了,而是数据规模和访问方式已经越过了它的舒适区。

取舍与边界

Bitmap 的收益来自密度。你把连续用户序号映射成 offset,它很香;你把稀疏业务 ID 直接扔进去,它会很贵。

典型问题:用机制化例子排查

  • 上线前估算最大 offset,而不是只估算置 1 的数量。
  • 对稀疏 ID 做连续映射或分桶,例如按日期、业务线拆 key。
  • STRLENMEMORY USAGE 看真实占用,不要只看 bit 数。
  • 大范围 BITOP 放到离线任务或低峰期,避免阻塞在线请求。

收束:一句判断

Bitmap 省的是密集布尔集合,不是任意稀疏空间。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。

我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。

如果你想继续跟完这套「图解 Redis」,欢迎关注公众号 「十三Tech」。后续会继续按数据结构、底层机制、持久化、高可用和实战排查这条线更新。

十三Tech公众号二维码