Redis Bitmap
Bitmap(位图)是 Redis 提供的一种用于处理二进制位(bit)的特殊数据结构,它基于 String 类型,每个 bit 代表一个布尔值(0 或 1),可以用于存储大规模的二值状态数据,如签到、活跃用户统计、去重等。
1. Bitmap 基本原理
- Bitmap 本质上是一个二进制数组,每个 bit 仅占 1 位,相比普通的 String 存储方式(每个字符 8 位),能大幅节省空间。
- Redis 并没有单独的数据类型 Bitmap,它是基于
String
结构的。 - 通过 位运算(
SETBIT
、GETBIT
、BITCOUNT
、BITOP
等)高效存取数据。
2. Bitmap 常用命令
(1)SETBIT:设置某一位的值
SETBIT key offset value
key
:键名offset
:bit 偏移量(从 0 开始)value
:0
或1
📌 示例
SETBIT user:1001 1 1 # 将 user:1001 的第 1 位设置为 1
SETBIT user:1001 2 0 # 将 user:1001 的第 2 位设置为 0
SETBIT user:1001 5 1 # 将 user:1001 的第 5 位设置为 1
假设 user:1001 初始状态是:(每个 0 代表 1 bit,总共 32 bit = 4 字节)
00000000 00000000 00000000 00000000
执行:
SETBIT user:1001 5 1 # 将 user:1001 的第 5 位设置为 1
SETBIT user:1001 5 1
结果变成:
00000100 00000000 00000000 00000000
第 5 位(从 0 开始计数,即第 6 个 bit)被设置为 1。
作用:类似于一个布尔数组,可用于表示某个用户在不同时间点的状态(如签到)。
(2)GETBIT:获取某一位的值
GETBIT key offset
key
:键名offset
:bit 偏移量
📌 示例
GETBIT user:1001 1 # 返回 1
GETBIT user:1001 2 # 返回 0
GETBIT user:1001 5 # 返回 1
作用:查询某个状态,如某用户是否签到。
(3)BITCOUNT:统计 bit 为 1 的个数
BITCOUNT key [start end]
key
:键名[start end]
(可选):字节范围(默认统计整个 key)
📌 示例
BITCOUNT user:1001 # 统计 user:1001 中 bit 为 1 的个数
作用:
- 统计某个用户的签到次数
- 统计一段时间内活跃用户数量
(4)BITOP:对多个 Bitmap 进行位运算
BITOP operation destKey key1 key2 ...
operation
:AND
(与)OR
(或)XOR
(异或)NOT
(非)
destKey
:存储结果的 keykey1 key2 ...
:参与运算的 key
📌 示例
BITOP AND active_users today yesterday # 统计连续两天都活跃的用户
BITOP OR total_active day1 day2 day3 # 统计三天内活跃过的用户
作用:
- 计算多天签到的交集、并集
- 统计活跃用户
3. Bitmap 典型应用
(1)用户签到
场景:每个用户有一个 31 位的 Bitmap(对应 31 天),bit 为 1
表示已签到,0
表示未签到。
📌 示例
SETBIT sign:1001:20240301 0 1 # 用户 1001 在 3 月 1 日签到
SETBIT sign:1001:20240302 1 1 # 3 月 2 日签到
SETBIT sign:1001:20240303 2 1 # 3 月 3 日签到
GETBIT sign:1001:20240303 2 # 查询 3 月 3 日是否签到(返回 1)
BITCOUNT sign:1001:202403 # 查询用户 1001 3 月签到次数
(2)统计活跃用户
场景:每天创建一个 Bitmap,记录活跃用户(bit 位置对应用户 ID)。
📌 示例
SETBIT active:20240301 1001 1 # 用户 1001 3 月 1 日活跃
SETBIT active:20240301 1002 1 # 用户 1002 3 月 1 日活跃
SETBIT active:20240302 1002 1 # 用户 1002 3 月 2 日活跃
BITCOUNT active:20240301 # 统计 3 月 1 日活跃用户数
BITOP AND active_both active:20240301 active:20240302 # 统计连续两天活跃的用户
(3)A/B 测试 & 用户权限控制
场景:用 Bitmap 存储用户是否属于 A/B 测试组或是否拥有某个权限。
📌 示例
SETBIT experiment:groupA 1001 1 # 用户 1001 参与 A 组测试
SETBIT experiment:groupB 1002 1 # 用户 1002 参与 B 组测试
GETBIT experiment:groupA 1001 # 查询用户 1001 是否在 A 组
4. Bitmap 优势
✅ 节省空间:1 个 bit 仅占 1/8 字节,非常适合存储大规模用户数据(如千万级别用户签到情况)。
✅ 高效查询:GETBIT
和 SETBIT
操作时间复杂度为 O(1),快速读写。
✅ 支持批量运算:BITCOUNT
、BITOP
等可进行高效统计。
5. Bitmap 限制
❌ 不支持删除某个 bit(只能置 0,无法真正删除)。
❌ 不支持范围查询(需要配合 BITCOUNT
和 GETBIT
)。
❌ 偏移量有限制(Redis 最大 String
长度约 512MB,即支持 2^32
个 bit)。
6. 总结
功能 | 命令 | 作用 |
---|---|---|
设置 bit | SETBIT key offset value | 设置指定偏移量的 bit |
获取 bit | GETBIT key offset | 获取指定偏移量的 bit |
统计 1 的数量 | BITCOUNT key | 统计 key 中 bit 为 1 的个数 |
位运算 | BITOP operation destKey key1 key2 | 对多个 Bitmap 进行 AND/OR/XOR/NOT 运算 |
Bitmap 非常适合用于海量用户数据的布尔状态存储,如签到、活跃用户、权限控制等场景。
参考文献
[1] https://redis.io/docs/latest/develop/data-types/bitmaps/