一、概念
什么是二值状态?二值状态就是元素只有0和1这两种情况,比如在签到的场景中只有签到和未签到两种,或者登陆的场景中只有已登录和未登录的情况。
Bitmap 的底层数据结构用的是 String 类型的 SDS 数据结构来保存位数组,Redis 把每个字节数组的 8 个 bit 位利用起来,每个 bit 位 表示一个元素的二值状态(不是 0 就是 1)。
可以将 Bitmap 看成是一个 bit 为单位的数组,数组的每个单元只能存储 0 或者 1,数组的下标在 Bitmap 中叫做 offset 偏移量。
8 个 bit 组成一个 Byte,所以 Bitmap 会极大地节省存储空间。 这就是 Bitmap 的优势。
二、判断登录状态场景
我们使用Bitmap来判断某个用户是否登录。Bitmap提供了GETBIT和SETBIT操作,通过一个偏移量offset对bit数组的offset位置的bit位进行读写操作,这个offset从0开始,我们还需要一个key来标记数据,将用户ID做为offset,已登录就设置1,未登录就设置0.
SETBIT命令:
SETBIT <key> <offset> <value>
GETBIT 命令:
GETBIT <key> <offset>
使用:
我们执行SETBIT loginStatus 1001 1 表示ID为1001的用户是已登录状态。接下来我们执行GETBIT loginStatus 1001 获取ID为1001的用户的登录状态。SETBIT loginStatus 1001 0设置ID为1001的用户退出登录。
三、用户每个月都签到场景
在签到统计中,每个用户每天的签到用 1 个 bit 位表示,一年的签到只需要 365 个 bit 位。一个月最多只有 31 天,只需要 31 个 bit 位即可。
key 可以设计成 uid:{userId}:{yyyyMM}
,月份的每一天的值 - 1 可以作为 offset(因为 offset 从 0 开始,所以 offset = 日期 - 1
)。
第一步:执行下面的指令表示记录用户在2023年6月25号打卡。
SETBIT uid:1001:202306 24 1
第二步:判断ID为1001的以后在2023年6月25号是否打卡
GETBIT uid:1001:202306 24
如何统计这个月首次打卡时间呢?
Redis 提供了 BITPOS key bitValue [start] [end]
指令,返回数据表示 Bitmap 中第一个值为 bitValue
的 offset 位置。
BITPOS命令:
BITPOS key bit [start] [end]
我们可以执行BITPOS uid:1001:202306 1 命令来获取2023年6月第一次打卡的时间
BITPOS uid:1001:202306 1
需要注意的是,我们需要将返回的 value + 1 ,因为 offset 从 0 开始。比如现在返回的是24我们需要加上1等于25,我们在前面设置是6月25号第一次打卡的。
四、小结
当我们遇到的统计场景只需要统计数据的二值状态,比如用户是否存在、 ip 是否是黑名单、以及签到打卡统计等场景就可以考虑使用 Bitmap。
只需要一个 bit 位就能表示 0 和 1。在统计海量数据的时候将大大减少内存占用。