首页/数据/Redis 进阶速查/Bitmap 位图签到与活跃标记
数据结构与选型42 条

Bitmap 位图签到与活跃标记

字符串按位寻址:SETBIT 标记、GETBIT 判断、BITCOUNT 统计,一年签到只需约 46 字节;BITOP 支持日/周/月位图与或运算。

Redis 进阶速查数据更新于 2026-10-13

Bitmap 是什么

Bitmap 不是独立的数据类型,而是把 String 当成位数组使用:SETBIT 把指定偏移量的位设为 0 或 1,GETBIT 读取单个位,BITCOUNT 统计为 1 的位数。它适合「大量对象的两态标记」场景,例如签到、活跃、开关位,因为每个对象只占一位。一年 365 天的签到,用日期做偏移量只需约 46 字节,用用户 ID 做偏移量则内存取决于最大 ID。

基本信息

底层类型String,按位寻址,offset 从 0 开始
内存公式总字节数约等于最大 offset 除以 8,向上取整
常用命令SETBIT / GETBIT / BITCOUNT / BITOP / BITPOS / BITFIELD
统计范围BITCOUNT 可只统计指定 BYTE 或 BIT 区间
多键运算BITOP AND|OR|XOR|NOT 把多个位图合并到目标键

典型使用场景

  • 连续签到统计:一个用户一条键,日期做偏移量,BITCOUNT 直接得月签到天数
  • 日活留存分析:每天一个位图,BITOP AND 求多日连续活跃,OR 求周活跃
  • 功能开关批量管理:按用户或设备编号标记是否开启某项实验能力
  • 去重标记:对象 ID 范围密集且状态只有两种时,位图比 Set 省一个数量级内存
  • 漏斗与留存报表的中间计算:把每日位图保留若干天后合并,避免每次重算

签到与活跃示例

签到与活跃示例
redis-cli SETBIT sign:20261012 10001 1        # 用户 10001 在当天签到
redis-cli GETBIT sign:20261012 10001          # 判断该用户是否签到
redis-cli BITCOUNT sign:20261012               # 当天签到总人数
redis-cli BITCOUNT sign:20261012 0 3           # 只统计前 4 个字节的范围
redis-cli BITOP AND active:week d:1 d:2 d:3    # 三天连续活跃的用户
redis-cli BITCOUNT active:week                 # 连续活跃人数
redis-cli BITPOS sign:20261012 0               # 第一个未签到用户的位偏移

命令与适用面

命令作用注意点
SETBIT设置某一位为 0 或 1offset 过大会一次性把键扩到对应长度
GETBIT读取某一位越界返回 0,不报错
BITCOUNT统计为 1 的位数支持按字节或位区间限定
BITOP多键按位运算并写结果目标键可以不是源键之一
BITPOS查找第一个指定值的位常用来找最早的未标记对象
稀疏位的代价:位图会按最大 offset 分配内存,如果用户 ID 是十几亿量级的稀疏编号,直接拿 ID 当 offset 会浪费巨量内存。工程上先做一层紧凑 ID 映射(编号从 0 递增),或改用 Hash 存活跃用户列表,按密度决定方案。
BITFIELD 可以把位图当作一组小整数使用,支持按指定宽度的有符号或无符号整数做自增与读写,适合在一段位里紧凑存放多个计数区间,避免为每个计数单独建键。

易错点

  • 用大额稀疏 ID 直接当 offset,一条键就占用数 MB 甚至更多,先做 ID 压缩或改用其他结构
  • 对超大位图执行整串 BITCOUNT,单次调用会扫描全部字节,需要按业务只统计必要区间或改用增量维护
  • BITOP 结果键与源键同名导致自引用,运算语义变得难以推理,结果键应使用独立名称
  • 把位图当作可回滚的状态存储:位只有 0 和 1,无法记录中间态与时间顺序,需要审计的场景应另存明细

数据来源与参考

  • Redis 官方文档:Bitmap 数据类型(SETBIT / BITCOUNT)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌